Summarize this documentation using AI
Overview
If your source of truth lives in MySQL, getting that data into Customer.io cleanly is what makes retention automation actually work—especially cart recovery, replenishment, and winback. If you want a second set of eyes on your schema-to-event mapping (or you’re tired of “why didn’t this person enter the flow?”), book a strategy call and we’ll pressure-test it like operators.
Most D2C teams don’t fail because they lack campaigns—they fail because the data entering Customer.io is inconsistent: emails change, orders arrive late, carts get overwritten, and segments stop matching. A solid MySQL → Customer.io feed fixes trigger reliability and keeps your audiences stable as you scale.
How It Works
At a high level, you’re turning rows in MySQL (customers, orders, carts, subscriptions) into two things inside Customer.io: people attributes for segmentation and events for triggering journeys. The win is simple: when data lands with consistent IDs and timestamps, your recovery and repeat-purchase automations stop guessing.
- People (profiles): MySQL customer records map to a Customer.io person. You’ll typically set attributes like
email,phone,first_name,created_at,last_order_at,total_orders,lifetime_value,sms_opt_in. - Events (behavior): MySQL operational tables (orders, fulfillments, refunds, cart tables) become events like
order_placed,order_fulfilled,refund_created,cart_updated,checkout_started. These events carry properties (order_id, items, value) and drive entry into workflows. - Identity resolution: Customer.io needs a stable identifier per person. In practice, you’ll pick a primary key (often
customer_idfrom MySQL) and treat email/phone as attributes that can change over time. This prevents duplicates when someone uses a new email at checkout. - Data mapping rules: You decide what becomes an attribute vs an event. Operator rule of thumb: if it’s used for ongoing segmentation, make it an attribute; if it’s used to start/advance a journey, make it an event.
- Trigger reliability: Customer.io triggers are only as good as your event timing. If your MySQL pipeline sends
order_placed30 minutes late, your “abandoned checkout” flow will misfire unless you add guardrails (like “exit if order_placed within last X minutes”).
Real D2C scenario: You run a 3-step cart recovery series. If MySQL writes carts to a single row per customer (overwriting items), and your feed only sends the “latest cart,” your first email might show the wrong products. Fix is to send cart_updated events with a cart snapshot (items array) and a stable cart_id, then trigger off the newest event per person.
Step-by-Step Setup
Before you touch Customer.io, get clear on what tables in MySQL represent “truth” for customers, orders, and carts. Most retention headaches come from stitching together half-truths across Shopify tables, custom checkout tables, and fulfillment systems.
- Pick your primary person identifier
- Use a stable MySQL key like
customer_idas the Customer.io personid. - Store
emailandphoneas attributes (and update them when they change).
- Use a stable MySQL key like
- Define your retention-critical event taxonomy
- Cart:
checkout_started,cart_updated,cart_abandoned(optional—often derived in Customer.io with time delays). - Purchase:
order_placed,order_paid(if you separate),order_fulfilled. - Post-purchase:
refund_created,subscription_created,subscription_canceled.
- Cart:
- Map MySQL columns to event properties and person attributes
- For
order_placed, include:order_id,order_total,currency,discount_code,items(SKU, name, qty, price),created_at. - For the person profile, compute attributes like
last_order_at,total_orders,lifetime_valuefrom MySQL (or your warehouse) and keep them updated.
- For
- Decide how data will be sent into Customer.io
- Operationally, teams either push near-real-time events (preferred for recovery) or do scheduled syncs (acceptable for LTV/segmentation updates).
- Keep “trigger events” (cart/order) as real-time as possible; keep “rollup attributes” (LTV, total_orders) on a schedule.
- Implement deduplication + ordering safeguards
- Send a unique
event_id(or deterministic key likeorder_id+ event_name) so retries don’t double-trigger. - Always include a trustworthy timestamp from MySQL (
created_at) so Customer.io can evaluate “within the last X hours” correctly.
- Send a unique
- Validate inside Customer.io before you build journeys
- Check a few known customers: do they have one profile (no duplicates), the expected attributes, and the expected recent events?
- Build a test segment like “Placed order in last 1 day” and confirm it matches reality from MySQL.
When Should You Use This Feature
MySQL as a data-in source is worth it when you need Customer.io to react to operational truth—not just what your ecommerce platform exposes in a UI. In most retention programs, we’ve seen MySQL feeds become the difference between “pretty flows” and flows that actually catch revenue.
- Cart recovery that doesn’t lie: Trigger on
checkout_startedfrom your checkout tables, not just a front-end pixel that misses Safari/iOS users. - Repeat purchase timing: Use
last_order_atand product-level purchase history (SKU) to drive replenishment and cross-sell at the right interval. - Reactivation with real suppression logic: Build winback audiences that exclude people with recent refunds, support issues, or chargebacks stored in MySQL.
- VIP segmentation that stays accurate: Keep
lifetime_valueandtotal_orderssynced so “VIP early access” doesn’t accidentally include one-time buyers.
Operational Considerations
This is where most teams get burned: not in the initial connection, but in the ongoing reality of data drift, late-arriving rows, and identity chaos. If the data entering Customer.io isn’t consistent, your segmentation and orchestration will degrade quietly.
- Segmentation depends on attribute freshness
- If you segment on
last_order_atbut only update it nightly, your “0–24h post-purchase” audience will be wrong all day. - Split your syncs: real-time events for triggers; scheduled rollups for analytics-style attributes.
- If you segment on
- Identity resolution breaks when email is treated as the ID
- In practice, this tends to break when shoppers use Shop Pay/Apple Hide My Email, then later purchase with a different address.
- Use
customer_idas the person ID and update email as an attribute; otherwise you’ll create duplicate people and split event histories.
- Event naming consistency matters more than you think
Order Placedvsorder_placedvsorderPlacedbecomes three different triggers. Pick one convention and enforce it.
- Late events will cause false positives
- If
order_placedarrives after your cart flow already sent step 1, you’ll annoy customers who already bought. - Use exit conditions and “wait until” checks (e.g., exit if
order_placedoccurs) and consider a short delay before the first cart message.
- If
- Item data shape impacts personalization
- If your items array doesn’t include stable keys (SKU/variant_id), product-level segmentation and dynamic blocks get fragile fast.
Implementation Checklist
If you want this to run without constant babysitting, treat the MySQL → Customer.io feed like production infrastructure. The checklist below covers the stuff that prevents silent failures and broken segments.
- Primary identifier selected (
customer_id) and documented - Email/phone treated as mutable attributes (not the ID)
- Event taxonomy finalized (cart, order, fulfillment, refund, subscription)
- Every event includes a reliable timestamp and a unique dedupe key
- Item arrays include SKU/variant_id, qty, price, product name
- Rollup attributes defined and refresh cadence set (hourly/nightly)
- Test segments created to validate matching logic against MySQL
- Cart recovery journey has exit conditions for purchase + refund edge cases
- Monitoring plan: alert on event volume drops and schema changes
Expert Implementation Tips
These are the operator moves that keep retention performance stable as volume grows and your stack gets messier.
- Send “state change” events, not just snapshots: For orders, emit
order_placedonce, then separate events fororder_fulfilledandrefund_created. It keeps journeys deterministic and debuggable. - Build a cart model that supports recovery: Prefer a
cart_id+ items snapshot per update. If you only store the latest cart row, your recommendations and product blocks will drift. - Keep your “golden” segmentation fields small: A handful of trusted attributes (last_order_at, total_orders, LTV, last_category_bought) beats 80 flaky ones that no one maintains.
- Use product-level events for repeat purchase: If you want replenishment, you need SKU/variant in the event payload. Otherwise you’ll end up doing blunt “30 days after any purchase” messaging.
Common Mistakes to Avoid
Most mistakes here aren’t dramatic—they’re subtle, and they show up as slowly declining recovery rates or random “why did they get this?” Slack threads.
- Using email as the primary ID, creating duplicate people when emails change
- Inconsistent event names across services (checkout service vs OMS vs warehouse)
- Missing timestamps, which breaks “within the last X” segment logic
- No deduplication, causing double sends when jobs retry
- Updating rollup attributes too slowly, making VIP and winback segments stale
- Triggering cart flows immediately without a short buffer, leading to messages during active checkout
Summary
MySQL data-in is worth doing when you need Customer.io to trigger off operational truth: carts, orders, and customer state changes. Get identity and event mapping right, and your segments stay accurate and your journeys fire reliably. If you get it wrong, you’ll spend your time debugging ghosts instead of shipping retention wins.
Implement Mysql with Propel
If MySQL is where your customer and order truth lives, the main job is translating that schema into clean people + events inside Customer.io without duplicates, late triggers, or brittle segments. When you’re ready, book a strategy call—we’ll walk through your tables, pick the right identifiers, and map the exact events/attributes that make cart recovery, repeat purchase, and reactivation flows dependable.