Migrating off Klaviyo — phase by phase.
Klaviyo migrations turn on three specifics: the Profiles + Events APIs use cursor pagination with a 10 req/sec burst limit, the Flows engine has no public 'export' so the trigger logic has to be rebuilt from the UI inventory, and your Shopify webhooks need to re-point in lockstep with the cutover or you'll double-charge customers' inboxes for a week.
The phases, tuned to Klaviyo
Each phase below is the Klaviyo-specific version of our standard playbook. Same shape every engagement, different specifics per SaaS.
Audience + Flow audit
1 weekWe inventory every active Flow, every Segment, every signup Form, and every SMS short code. Most stores have 20+ Flows that compounded over years — about half are no longer firing or are sending to inactive segments.
✓Screenshot every active Flow as a single-page reference (the API can't export the trigger logic)✓List every Segment with its filter rules and current size✓Inventory active Forms (popups, embedded) and their UTM rules✓Audit SMS senders (short codes vs long codes, carrier compliance state, opt-in records)✓Map Shopify webhooks currently firing into Klaviyo (orders, refunds, abandoned checkouts, fulfillment)You walk away withA Flow Inventory + Segment Catalogue + the Shopify webhook switchover plan.
Schema + suppression model
1 weekProfiles get a single Postgres table, deduped on email and phone with a unique index. Suppression and unsubscribe state flip booleans instead of inflating a bill. We preserve the Klaviyo `profile_id` for backwards compatibility with anything pointing at it.
✓Design `profiles` table with dedupe on (lower(email)) and (E.164 phone)✓Design `events` (or `profile_events`) table for the activity stream✓Design `suppressions` with reason codes (hard bounce, unsubscribe, complaint, manual)✓Plan the SMS sender flow direct to Twilio (no Klaviyo markup) + 10DLC / short-code compliance✓Decide attribution windows up front so reporting agrees with Shopify + GA4 from day oneYou walk away withSchema migrations + a documented attribution model + a Twilio sender plan.
Extract via Klaviyo APIs
1-2 weeksProfiles, events, lists, segments and metrics come out via the v2024-XX REST APIs. Throttling matters here — burst at 10 req/sec, sustained ~150 req/min, and segment-level extraction is a separate dance.
✓Authenticate via a Private API Key (server-side only)✓Paginate profiles with the `page[cursor]` parameter (the JSON:API style)✓Pull every event with a `filter=greater-than(datetime,…)` window — chunk by date or you'll time out✓Extract list and segment memberships separately (segments aren't materialised; you re-derive them)✓Throttle to stay under the burst + steady-state limits; the cursor lets you resumeYou walk away withA re-runnable extract script + a reconciliation report against Klaviyo's own dashboard.
Build + weekly demos
3-5 weeksThree Flows ship in week one (welcome / abandoned cart / post-purchase). Templates become React Email components in your repo. SMS goes direct to Twilio. By end of phase your team is sending the weekly newsletter from the new product.
✓Build the Flows engine on Inngest — every step a typed function with retries✓Templates as React Email / MJML, version-controlled, previewed in CI against Litmus✓Email sends via Amazon SES or Resend (fractions of a cent per send, no contact-tier multiplier)✓SMS via Twilio direct — no markup, you handle 10DLC / short-code registration once and own it✓Reporting in Metabase against the same Postgres — drill-downs agree with the chartYou walk away withThree live Flows + weekly campaigns running from the new product on a staging domain.
Parallel run + Shopify cutover
1-2 weeksShopify continues to fire webhooks into Klaviyo for a fortnight while the new product mirrors them. Daily reconciliation compares opens, clicks, conversions. Then we switch the webhook endpoints on a Tuesday morning.
✓Dual-write Shopify webhooks via a Cloudflare worker (Klaviyo + new endpoint)✓Daily reconciliation: sends, opens, clicks, attributed revenue✓Move SMS sender identity (short code or 10DLC long code) — the carrier paperwork is the long pole, start week 1✓Suppress all but one Klaviyo Flow during the final week so we're not double-sending✓Cut Shopify webhook endpoints to the new product, leave Klaviyo on as read-onlyYou walk away withA reconciliation dashboard showing seven days of zero drift + a signed sign-off from the head of marketing.
Cutover + Klaviyo read-only
1 day + 90-day fallbackKlaviyo Flows get paused (not deleted — kept for compliance), Shopify webhooks point cleanly at the new endpoints, the SMS sender identity moves over, auto-renewal cancelled.
✓Pause every Klaviyo Flow (don't delete — Klaviyo holds the unsubscribe records you may need)✓Confirm SMS sender identity has fully migrated to Twilio✓Verify Shopify webhook delivery to the new endpoints with synthetic events✓Lock Klaviyo to read-only / viewer role✓Cancel Klaviyo auto-renewal in writingYou walk away withCutover Runbook + a confirmed SMS sender migration + a quiet inbox where the renewal email used to land.
The Klaviyo APIs we'd actually hit
Concrete endpoints we use to extract your data during the parallel-run phase. We keep the extract scripts — they're useful at every renewal.
GET https://a.klaviyo.com/api/profiles/GET https://a.klaviyo.com/api/events/GET https://a.klaviyo.com/api/metrics/GET https://a.klaviyo.com/api/lists/GET https://a.klaviyo.com/api/segments/GET https://a.klaviyo.com/api/lists/{list_id}/profiles/GET https://a.klaviyo.com/api/campaigns/GET https://a.klaviyo.com/api/flows/The Klaviyo-specific gotchas
Things we've learnt the hard way (or that the documentation understates). We'll surface these on the kickoff call so nobody is surprised in week 6.
- ⚠API rate limits are revision-pinned and ~10 req/sec burst, ~150 req/min steady-state. The events extract is the long pole — chunk by date window and respect the cursor.
- ⚠API revisions are pinned via the `revision: 2024-XX-15` header. Pin the revision in your client and don't auto-upgrade or breaking changes will land mid-migration.
- ⚠Flow logic isn't exportable — you can list Flows and their metadata, but the trigger conditions and step branching are UI-only. Inventory exhaustively in Phase 1.
- ⚠Suppression state is split across hard bounces, unsubscribes, manual suppressions and complaints — pull all four with reason codes preserved or you'll resend to bounces and damage deliverability.
- ⚠SMS sender identity (short code or 10DLC) is the longest lead-time item — start the Twilio paperwork in week one or the cutover stalls waiting on carrier approval.
- ⚠Shopify webhook order matters: orders, refunds, fulfilment can arrive out-of-sequence. Idempotency keys on every write or you'll double-fire abandoned-cart emails.
- ⚠Predictive Analytics (CLV, churn risk) is closed-source on Klaviyo's side — we replace it with explicit SQL on order history, not a copy of the model.
What stays where it is
Migrations work because they're scoped honestly. Here's what we don't move — by design.
- ·Klaviyo's CDP product — most stores don't actually use it; we sync direct from Shopify / your warehouse
- ·Reviews — handled by a dedicated tool (Stamped, Junip, Yotpo) if you need it, not bundled
- ·Predictive Analytics models — replaced with explicit SQL definitions you can read
- ·Mobile push and in-app messages — scoped separately if mobile is a real channel
- ·Klaviyo's native A/B testing UI — replaced with feature flags on the send template
- ·Klaviyo Forms templates — your popups become first-party React components on your own domain
Get a Klaviyo-shaped migration plan.
Tell us your seat count, contract end date, and the integrations you can't lose. We'll come back within a business day with a fixed-price scope and a timeline tuned to your renewal.
Scope a Klaviyo migration
One business day. NDA + DPA on request.