Customer.io → Klaviyo
Export Customer.io people, import consented profiles into a Klaviyo list, and load suppressions separately. Turn list-triggered flows to manual first, because a CSV upload does not ask for double opt-in.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
Customer.io
- People, attributes, and events drive campaigns without a separate list for every segment
- Audience, campaigns, automations, and reporting live in one publishing system
- Journeys, Liquid, and event history have to be rebuilt, and a CSV import can fire automations while it runs
- Automation logic, analytics history, and deliverability settings are not very portable
Klaviyo
- Commerce-native segmentation, behavioral automation, and revenue attribution are exceptionally strong
- Audience, campaigns, automations, and reporting live in one publishing system
- Data-model complexity and profile-based pricing can become expensive and difficult to unwind
- Automation logic, analytics history, and deliverability settings are not very portable
Klaviyo: Commerce-native segmentation, behavioral automation, and revenue attribution are exceptionally strong. This removes a major source-side concern: Journeys, Liquid, and event history have to be rebuilt, and a CSV import can fire automations while it runs.
What you lose: People, attributes, and events drive campaigns without a separate list for every segment. What you inherit: Data-model complexity and profile-based pricing can become expensive and difficult to unwind.
Jump to a section
Know the shape of the move.
This timeline assumes
- One Customer.io workspace and one Klaviyo account. The Klaviyo user can import contacts and export profiles.
- Each subscriber CSV is 50 MB or smaller. Klaviyo says to split anything larger. An export can include at most 700 columns.
- You have consent for every address in the subscriber file. Klaviyo's upload does not run double opt-in.
- The site already documents Customer.io → Mailchimp. Pick one destination and pause the other.
- List-triggered flows are manual before the upload. No live flow sends until the seed check passes.
What survives the move.
“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.
| Item | Outcome | Impact | What happens | Mitigation |
|---|---|---|---|---|
| Consented people | partial | critical | Klaviyo's migration article says to put email in a column named Email or Email Address, keep unsubscribes out of that file, and import from the list's Manage list menu. The first column should be the email. | Export only people you may mail. Map Email. Choose Apply bulk consent only when every row has that consent. |
| Unsubscribes | partial | critical | Customer.io uses one unsubscribed boolean for email, SMS, WhatsApp, and push. Klaviyo wants unsubscribed and bounced addresses out of the subscriber CSV and imported as suppressions. | Export unsubscribed true on its own. Import suppressions before you send. Do not apply email bulk consent to that file. |
| Attributes | partial | high | A Customer.io people export can be all attributes or a chosen set. Klaviyo maps columns to profile properties. A new property replaces the old value. Blank cells do not clear an existing property. | Export only the properties you will segment on. Check data types while mapping. |
| Events | lost | high | The people CSV is not event history. Klaviyo's list export also cannot include full event history. Old Customer.io events will not drive Klaviyo flows. | Start events from the site or store after cutover. Archive a few person JSON exports if you must audit someone. |
| Campaigns and Liquid | lost | critical | Customer.io campaigns do not become Klaviyo flows. You rebuild the messages. | Rebuild the flows you will run this month. Leave them manual until the seed send. |
| Segments | manual | high | Exporting a Customer.io segment gives you the people and a membership time. Klaviyo will not recreate the segment definition. | Rebuild the definition from profile properties, or import that file to a list if the segment is really a static list. |
| List-triggered flows | manual | critical | Klaviyo says to turn off flows triggered by the list unless you want them to send to every imported contact. Uploads do not trigger double opt-in. | Set those flows to manual before Upload. Read the consent step. Use Only import the consent in my file when the CSV already has it. |
| File size and columns | manual | high | Subscriber CSV uploads must be 50 MB or less. A later Klaviyo export of the list allows 700 columns and keeps downloads for 30 days. | Split the Customer.io export. Drop columns you will not map. |
| Push devices | lost | medium | Customer.io can export devices. This Klaviyo list import does not register them. | Keep push on Customer.io or plan a separate push tool. |
| Duplicate emails | manual | high | Customer.io can store one email on more than one id. Klaviyo folds an import into one profile per email. | Export Customer.io duplicates first and choose which attributes win. |
| Predictive analytics and consent columns | partial | medium | A Klaviyo list export can include consent timestamps and, when the account qualifies, predictive fields. Those do not exist on day one of an import. | Do not compare predictive fields to Customer.io. Check email consent status instead. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Customer.io email | Klaviyo Email | automatic | Name the column Email or Email Address. Put it first. |
| Consented people | List profiles with email consent | transform | Apply bulk consent only if every row agreed. |
| unsubscribed true | Suppression, not the subscriber list | transform | Klaviyo's migration article says to keep these out of the subscriber CSV. |
| Chosen attributes | Profile properties | transform | New values replace old ones. Blanks do not clear them. |
| id | A custom property | manual | Useful for support. Klaviyo still keys the profile on email. |
| Segment export | A list or a rebuilt segment | manual | The membership timestamp is not a definition. |
| Campaigns | No destination | unsupported | Rebuild flows and leave them manual during import. |
| Events | No destination | unsupported | Neither CSV carries full event history. |
| Devices | No destination | unsupported | Push stays where it is until you move it on purpose. |
Make the move recoverable.
Create the source-of-truth backup
Keep Customer.io people, opt-outs, and a list of live campaigns before Klaviyo uploads anything.
- Export consented people and unsubscribed people as separate CSVs.
- Export duplicate people.
- List Klaviyo flows triggered by the destination list and set them to manual.
- Download the Customer.io files. They leave the workspace after 60 days.
- Store checksums.
Proof to capture: Row counts, the flow list with manual mode, and checksums.
Build a subscriber CSV and a suppression CSV
Follow Klaviyo's split between people you can mail and people you cannot.
- Export unsubscribed true with email and the id.
- Export everyone you have email consent for. Name the email column Email.
- Split any file over 50 MB.
- Remove duplicate emails after you pick a winning id.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Import into a quiet Klaviyo list
Add profiles without sending a flow to the whole file.
- Set flows triggered by this list to manual.
- Import suppressions first, using the path in Klaviyo's migration article.
- Import the subscriber CSV. Map columns. Apply bulk email consent only when the whole file has it.
- Wait for the import to finish. Then sample consent before you set any flow live.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
The things most likely to hurt.
These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.
The list upload sends a flow
Klaviyo tells you to turn off list-triggered flows unless you want them to mail every imported contact.
- Consequence
- The whole file gets a welcome or a browse flow.
- Mitigation
- Manual mode first. Import suppressions before subscribers.
Stop if: Any flow on that list is still live.
Bulk consent overstates permission
Apply bulk consent marks the file as consented. Uploads do not run double opt-in.
- Consequence
- You mail people who never opted in.
- Mitigation
- Use the consent already in the file when you are unsure. Keep unsubscribes out of this CSV.
Stop if: You cannot point at a consent source for every row.
Customer.io keeps sending
Importing to Klaviyo does not stop Customer.io campaigns.
- Consequence
- People get both.
- Mitigation
- Stop Customer.io campaigns before Klaviyo flows go live.
Stop if: A Customer.io campaign is still scheduled.
Do the work in this order.
- Day 1 · export
Export consented people and opt-outs
2 hours active1 day elapsedCustomer.io export email waiting- Export both filters.
- Export duplicates.
- List Customer.io campaigns that are live.
Stop / go checkpointDo you have two clean files?
Go when: Opt-outs and consented people are separate, and both are downloaded.
Stop when: The files are mixed or still over 50 MB.
- Day 2 · quiet
Make the Klaviyo list quiet
1 hour active1 day elapsedNone waiting- Create or open the destination list.
- Set list-triggered flows to manual.
- Confirm you can import contacts.
Depends on: export
Stop / go checkpointCan you upload without sending?
Go when: Every flow on that list is manual.
Stop when: A flow is still live.
- Day 3 · import
Import suppressions, then subscribers
2 to 4 hours active1 day elapsedKlaviyo import waiting- Import the suppression file.
- Import subscribers and map properties.
- Sample consent on both sides.
Depends on: quiet
Stop / go checkpointDid consent land?
Go when: Opt-outs are suppressed and subscribed counts match.
Stop when: An opt-out can receive email marketing.
- Day 4 · rebuild
Rebuild one flow and seed it
3 hours active1 day elapsedNone waiting- Rebuild the next flow, still manual.
- Stop Customer.io sends.
- Send a seed.
Depends on: import
Stop / go checkpointIs the seed the only mail?
Go when: Seeds get one message and Customer.io sent nothing.
Stop when: A flow mailed the imported list.
- Day 5 · cutover
Turn on one flow
1 hour active1 day elapsedThe first live sends waiting- Import the last delta, suppressions first.
- Set one flow live.
- Check suppressions again the next day.
Depends on: rebuild
Stop / go checkpointLeave the flow live?
Go when: One flow is live, Customer.io is stopped, and opt-outs stayed suppressed.
Stop when: Consent or a double send fails.
Cut over with a way back.
Cutover
Let one Klaviyo flow send, with Customer.io quiet and opt-outs suppressed.
- Stop Customer.io campaigns. Record the time.
- Re-export new opt-outs and import suppressions.
- Import new consented profiles.
- Turn on a single Klaviyo flow.
- Watch the first hour for sends to suppressed profiles.
Proof to capture: Stop time, both import results, and the one live flow.
Rollback
Put sends back on Customer.io if Klaviyo consent or a flow mis-fires.
- Set the Klaviyo flow back to manual.
- Do not delete Customer.io people.
- Write any new Klaviyo unsubscribes back to Customer.io as unsubscribed true.
- Restart a Customer.io campaign only when you know it will not replay old triggers.
- Name the single sender.
Proof to capture: Klaviyo flows are manual and Customer.io is the only scheduled sender.
- A Customer.io opt-out received Klaviyo mail.
- A list-triggered flow sent during the upload.
- Bulk consent was applied to a file you cannot defend.
- Customer.io still has a campaign scheduled.
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
FIL-01Blocking | Size and split | Check each subscriber CSV is 50 MB or under and starts with Email. | Every file passes those two rules. | File sizes and the header row. | |
SUP-01Blocking | Opt-outs are suppressed | Sample 20 unsubscribed emails in Klaviyo. | They cannot receive email marketing. | The sample and profile consent panels. | |
SUB-01Blocking | Subscriber count | Compare the consented CSV with the list count. | Counts match, or each gap is logged. | Both numbers. | |
FLO-01Blocking | Manual during import | Read flow status for the list at import time. | None were live while the CSV uploaded. | Flow status notes with times. | |
DUP-01Blocking | One email each | Scan the subscriber file for duplicate emails. | No duplicates. | The scan result. | |
CIO-01Blocking | Customer.io is quiet | Open campaigns and broadcasts. | Nothing is scheduled. | Screenshots. | |
SEED-01Blocking | Seed | Send the rebuilt flow to seed profiles only. | One message, working unsubscribe, no Customer.io copy. | Headers. | |
PROP-01 | A mapped attribute | Open one imported profile and compare a property to the CSV. | The value matches. A blank in the file did not wipe an older value you meant to keep. | The profile panel. |
Remove the scaffolding safely.
Safe after: One live Klaviyo flow has run, opt-out samples still hold, and Customer.io has stayed quiet for a day.
- Archive the Customer.io CSVs outside the workspace.
- Leave Customer.io campaigns stopped.
- Keep unused Klaviyo flows manual or delete the drafts you will not use.
- Remove export-only users.
- Write the next review date.
Verify against the primary material.
Platform behavior changes. Check these sources and the review dates above before executing a production migration.
- Customer.io: export people dataAccessed 2026-11-06
- Customer.io: global unsubscribesAccessed 2026-11-06
- Klaviyo: migrate subscribers and unsubscribesAccessed 2026-11-06
- Klaviyo: import subscribers to a listAccessed 2026-11-06
- Klaviyo: export a list or segmentAccessed 2026-11-06