Skip to main content
Customer.io works like a full customer data platform, not just an email tool. It has profiles, attributes, events, and objects across two separate APIs. Its messages use Liquid, a real templating language rather than simple merge tags. That’s why this guide has more steps than the Mailchimp or Loops one. Read the Concepts table first, it saves time. This guide assumes your Brew brand and sending domain are set up. If not, verify your domain first. DNS changes can take up to 72 hours. Customer.io also uses Entri for automatic domain setup, the same DNS-connection partner Brew uses. That part of the process should look familiar.
Looking to go the other way, designing in Brew and sending from Customer.io? See the Customer.io integration instead.
Rule for the whole migration: only one platform sends live email to a given contact at a time.

Concepts

1. Export Profiles From Customer.io

Every marketing recipient must have opted in to hear from you. Importing or syncing contact data into Brew is not permission to email it. See What You Can Send.
Go to the Profiles page and click Export to CSV. Choose all attributes, displayed attributes, or specific attributes. Filter to a segment first if you only want a subset. Customer.io gives you one CSV, not the status-split export Mailchimp uses. The suppression list isn’t self-serve. Email Customer.io’s support team to request it. They return a SHA-256 hashed CSV with a compare tool rather than a plain list. Request this early, it adds lead time the rest of the migration doesn’t have. Use the compare tool to identify which of your exported profiles are suppressed. Mark those rows Subscribed: false before importing, so Brew never sends to them. Brew’s importer also never re-subscribes a contact who previously unsubscribed.

2. Map Your CSV

Notes:
  • Customer.io reserves five names that won’t map 1:1 to Brew’s own reserved names: id, email, phone, created_at, unsubscribed. Rename collisions before mapping
  • Brew’s reserved names are created_at, updated_at, email, first_name, last_name, source, subscribed
Personalization. This step needs real judgment, not just a syntax swap. Simple attribute substitution translates cleanly, into a Brew merge tag with a built-in fallback:
Everything past that needs a manual rebuild rather than a renamed tag:
  • {% if %}...{% else %}...{% endif %} conditional blocks
  • Journey attributes ({{ journey.attribute }}), temporary values scoped to a single workflow run, which have no Brew equivalent
  • Object and relationship loops ({% for class in objects.online_classes %}), tied to Customer.io’s Objects data model, which Brew doesn’t have
  • Snippets ({{ snippets.footer }}), reusable blocks, which you rebuild as standing instructions on your brand instead
Event and trigger properties do have an equivalent. {{ event.property }} and {{ trigger.data.property }} become {{ property }}, referencing the payload schema you define on the trigger event. See merge tags. If a template used only simple substitution, migration is mechanical. If it used any of the rest, budget real time to rebuild the logic.

3. Import Into Brew

Audience → Add contacts → CSV Upload. Map columns, tick validation if the list hasn’t been checked recently, review, then import. See Add Contacts.

4. Rebuild Segmentation

Data-driven segments are the one real structural difference from Mailchimp or Loops. Customer.io segments can filter directly on event history. Their own example is a segment for profiles with no login in 30 days. It’s built straight off a page_viewed event with no derived field required. Brew Audiences filter on three things: contact properties, subscription status, and email engagement (opens, clicks, and sends). They can’t filter on other event history directly. To rebuild a segment based on event history:
  1. Write the derived signal onto the contact as a custom property, using an automation or the API on whatever cadence fits.
  2. Build your Brew Audience on that property, not on the raw event.
Before cutover, spot-check that a recreated Audience’s membership count is in the right ballpark against the original segment. A wrong translation can undercount or overcount who gets an email, and that isn’t always visible in the UI. Manual segments don’t have a direct equivalent. Brew has one subscription state per contact, subscribed or unsubscribed. There are no opt-in categories and no subscriber-facing preference center. Marketing emails and automations respect that flag, and transactional sends bypass it. Rebuild each manual segment as a custom property plus an Audience filtered on it. If people opted into it themselves, note that Brew can’t reproduce that self-service control. Decide how to honor the original consent before your first send.

5. Rebuild Templates

Open Emails in the sidebar, then use the Import tools on the right side of the canvas. See Importing existing designs. Set your brand identity once: logo, colors, fonts, and voice pulled from your site. Every rebuilt template inherits it automatically, which beats hand-porting markup with Liquid still embedded in it.

6. Rebuild Automations

Test-fire before publishing, and leave every rebuilt automation unpublished until cutover day. Build an Automation covers the trigger setup and the test step.

7. Swap the API Calls in Your Code

Customer.io splits its API in two. The Track API uses a Site ID and Track key to identify people and record events. The App API uses a bearer key for transactional sends and API-triggered broadcasts. Brew uses one bearer key for everything, with no split credentials to manage. Identify and track. These calls power every automation, not just transactional ones. Before, with Customer.io’s Track API:
After, with Brew:
The pattern stays the same whatever kind of email the automation sends. What changes is which automation receives the event, not this code. Direct sends. Customer.io has two direct-send methods, transactional sends and API-triggered broadcasts. Both are a single App API call to different endpoints. In Brew both become the same trigger-plus-payload pattern. Before, with Customer.io’s App API:
After, with Brew, both become a fire call against whichever automation you built for that trigger:
Derive the Idempotency-Key from something stable about the action, like the user id above. A key built from a timestamp changes on every retry, which defeats the point and lets a retry send twice. See Idempotency. One exception: a broadcast aimed at a whole saved segment isn’t a per-recipient event. Use a manual-audience automation run, POST /v1/automations/{automationId}/run, or send a one-off Email to an Audience instead. The fire endpoint is for per-recipient triggering. Full request shapes are in the API reference. This section shows the shape of the migration, not a copy-paste replacement for your code.

8. Cut Over

  1. Warm up your Brew sending domain before any real volume. Send to your most engaged contacts first and ramp over several days. Gradual send does the ramping for you.
  2. Rebuild contacts, segments, templates, and automations while Customer.io keeps sending normally.
  3. Move one message type at a time. A reasonable order is broadcasts first, then automations, then transactional.
  4. Give single-recipient, account-critical messages extra care, whichever category they’re in. A password reset or a receipt qualifies.
  5. Watch each moved type in analytics before you move the next.
  6. Confirm recreated segments’ membership counts before their automations go live. See Step 4.
  7. Point signup forms, event tracking, and inbound integrations at Brew once everything upstream is verified.
  8. Keep Customer.io active but unused for a couple of weeks as a fallback, then downgrade or cancel.
Never leave the same message type live in both places at once.

Quick Reference

Need Help?

Our team is ready to support you at every step of your journey with Brew. Choose the option that works best for you:

Search Documentation

Type in the “Ask any question” search bar at the top left to instantly find relevant documentation pages.

ChatGPT/Claude Integration

Click “Open in ChatGPT” at the top right of any page to explore it further with ChatGPT or Claude.