Looking to go the other way, designing in Brew and sending from Customer.io? See the Customer.io integration instead.
Concepts
1. Export Profiles From Customer.io
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 rowsSubscribed: 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
{% 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.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 apage_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:
- Write the derived signal onto the contact as a custom property, using an automation or the API on whatever cadence fits.
- Build your Brew Audience on that property, not on the raw event.
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: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
- 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.
- Rebuild contacts, segments, templates, and automations while Customer.io keeps sending normally.
- Move one message type at a time. A reasonable order is broadcasts first, then automations, then transactional.
- Give single-recipient, account-critical messages extra care, whichever category they’re in. A password reset or a receipt qualifies.
- Watch each moved type in analytics before you move the next.
- Confirm recreated segments’ membership counts before their automations go live. See Step 4.
- Point signup forms, event tracking, and inbound integrations at Brew once everything upstream is verified.
- Keep Customer.io active but unused for a couple of weeks as a fallback, then downgrade or cancel.
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:- Self-Service Tools
- Talk to Our Team
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.