App guides
The Customer.io app sends your store's customers to Customer.io as people, and what they do as events: orders, shipments, abandoned carts and subscription changes. Use the events to trigger campaigns, and the customer's attributes, such as order count, total spent and marketing opt-in, to build segments.
Data goes one way, from Swell to Customer.io, as it happens. The app reads your store and doesn't change your customers, orders or other records.
| When | What the app does |
| A customer is created, or details the app sends change | Creates or updates the person in Customer.io, identified by the Swell customer ID. |
| An order is placed, paid, fails to pay, is fully fulfilled, fully refunded or canceled | Sends Order Completed, Order Paid, Order Payment Failed, Order Fulfilled, Order Refunded or Order Cancelled. |
| A shipment is created | Sends Order Shipped with the carrier, tracking code and shipped items. |
| Swell marks a cart abandoned | Sends Cart Abandoned with the products and the checkout link, if the cart has a customer. |
| A subscription starts, is paid, fails to pay, nears the end of its trial, is paused, resumed, canceled or completed | Sends the matching Subscription event. |
| You choose Sync existing customers or Send to Customer.io | Sends the current details of all customers, the selected ones, or one. |
| Customer.io refuses the Site ID or API key | Emails the store's admins, and keeps retrying the events for up to 48 hours. |
Each event is sent in the same request as the customer's current details, with the person first.
- A Customer.io account and a workspace for your store. For the test environment, a separate workspace, so test customers and orders stay out of your live campaigns.
- Access to the workspace's Track API keys in Customer.io: the Account Admin role, or a Member with the Manage API credentials permission.
- Reference people by set to cio_id or id in your Customer.io workspace settings. The app identifies people by their Swell customer ID, and Customer.io accepts email changes for a person identified by ID only with this setting.
Install Customer.io from the Swell App Store, and set it up in your test environment before the live one.
Copy your Track API key
In Customer.io, go to Account Settings > API Credentials, find the Track API key of your workspace, and copy its Site ID and API Key. An App API key doesn't work here.
Add it to the app
In Swell, go to Apps > Customer.io > Settings, paste the values in Site ID and API key, and click Save settings. The app finds whether your workspace is in the US or EU data center from the keys, and saves it in Data center.
Test the connection
Click Test connection. The message names your workspace and its data center. If Customer.io doesn't accept the keys, the message says so.
Turn on sending
Turn on Send data to Customer.io and click Save settings. From then on, new and changed customers and their events are sent as they happen. Events aren't sent while it's off, and aren't sent later.
Send your existing customers
In Apps > Customer.io, choose Actions > Sync existing customers, then Start sync. The sync runs in the background and sends every customer as a person. Past orders and carts aren't sent.
Place a test order
Place a test order as a customer. In Customer.io, find the customer under People and open their Activity tab. It shows the attribute changes and Order Completed with the order's data.
Go live
Settings are saved separately for each environment. In the live environment, repeat steps 1 to 5 with the Track API key of your live workspace. Keep a separate Customer.io workspace for the test environment, so test orders don't start your live campaigns.
Each Swell customer is a person whose id is the Swell customer ID. The person is created when the customer is created, and updated when one of the details below changes and with every event the app sends. Account updates that change none of them, such as a login, aren't sent.
| Attribute | From Swell |
| email, first_name, last_name, name | The customer's email and name. |
| phone_number | The customer's phone number. |
| created_at | When the customer was created. |
| account_type, customer_group | The customer's type and group. |
| locale, currency | The customer's locale and currency. |
| country, state, city | The default shipping address, or the billing address if the shipping address has no country. |
| email_optin, sms_optin | The email and SMS marketing opt-ins, always true or false. |
| order_count, order_value | The number of orders and the total spent. |
| first_order_at, last_order_at | The dates of the first and last orders. |
| cart_abandoned_count, last_cart_abandoned_at | The number of abandoned carts and the date of the last one. |
| account_balance | The customer's account balance. |
| unsubscribed | Sent only when the customer's email opt-in changes in Swell. |
Dates are Unix timestamps in seconds, so they work in Customer.io's date conditions. Text longer than 900 characters is cut. When a field is emptied in Swell, the attribute is removed in Customer.io.
The phone number is sent as phone_number, not as phone, which Customer.io uses as an identifier by default. Swell customers can share a phone number, and as an identifier it would put customers with the same number on one person.
Customer.io's unsubscribed attribute is sent only when a customer's email opt-in changes in Swell: true when they opt out, and false when they opt in. Other updates, events and the sync actions don't send it, so an unsubscribe made through a Customer.io message stays in place unless the customer opts in again in Swell.
A new customer who hasn't opted in arrives with email_optin set to false, and the app doesn't unsubscribe them in Customer.io. To keep marketing to customers who opted in, add the condition email_optin is true to your marketing campaigns and segments. Messages about an order or shipment don't need it.
| Event | Sent when |
| Order Completed | An order is placed. |
| Order Paid | An order is paid in full. |
| Order Payment Failed | A payment for an order fails. |
| Order Fulfilled | An order is fully fulfilled. |
| Order Refunded | An order is fully refunded. Partial refunds aren't sent. |
| Order Cancelled | An order is canceled. |
Order events carry order_id, order_number, status, currency, subtotal, discount, coupon, shipping, tax, total, item_count, paid, payment_total, refund_total, payment_method, guest, subscription_id, shipping_method, shipping_address, comments, cancel_reason, ordered_at and products. Each product has product_id, variant_id, sku, name, variant, slug, price, quantity, total and image_url. The shipping address has name, address1, address2, city, state, zip, country and phone.
Amounts are in the order's currency, not in cents. Properties without a value in Swell are left out, except paid and guest, which are always true or false. Orders created by a subscription have subscription_id. Draft orders and orders without a customer aren't sent.
Order Shipped is sent for each shipment created for an order, partial shipments included. A shipment that's canceled by the time the event is sent is skipped.
It carries order_id, order_number, shipment_id, shipment_number, carrier, service, tracking_code, estimated_delivery_at, currency, shipping_address and products. The products are the shipped items, with the quantity shipped and no total.
Cart Abandoned is sent when Swell marks a cart abandoned, 3 hours after the cart last changed, or after the delay set for the abandoned cart email in Settings > Notifications. Swell marks carts abandoned whether that email is on or off.
It carries cart_id, checkout_url, currency, subtotal, discount, coupon, shipping, tax, total, item_count, abandoned_at and products. checkout_url brings the shopper back to their cart. In a campaign triggered by the event, use {{event.checkout_url}} for the link.
- Only carts linked to a customer are sent. A cart without one, such as a cart before the shopper enters an email, has nobody to message.
- A cart isn't sent if the shopper came back to it or placed the order before the event was sent.
- A cart that's abandoned again after the shopper comes back sends Cart Abandoned again.
- If Customer.io sends your abandoned-cart emails, turn off Abandoned cart in Settings > Notifications, so customers don't get both. Do the same for other Swell emails you replace with Customer.io messages.
| Event | Sent when |
| Subscription Started | A subscription becomes active, or a canceled subscription is restored. |
| Subscription Paid | A subscription's billing period is paid. |
| Subscription Payment Failed | A subscription charge fails. |
| Subscription Trial Ending | 3 days before a subscription's trial ends. |
| Subscription Paused | A subscription is paused. |
| Subscription Resumed | A paused subscription is resumed. |
| Subscription Cancelled | A subscription is canceled. |
| Subscription Completed | A subscription with a fixed number of billing periods ends. |
Subscription events carry subscription_id, subscription_number, status, plan_name, interval, interval_count, currency, price, quantity, coupon, total, recurring_total, trial, trial_end_at, period_start_at, period_end_at, payment_expiring_at, payment_retry_at, paused_at, pause_end_at, canceled_at, cancel_at, cancel_reason and products. The first product is the subscription's product, followed by any items added to the subscription. trial is always true or false. Draft subscriptions aren't sent.
Once Send data to Customer.io is on, customers are sent when they're created or change. To send customers now:
- To send every customer, go to Apps > Customer.io, choose Actions > Sync existing customers, and click Start sync.
- To send some customers, select them in the customer list, choose Send to Customer.io, and click Send.
- To send one customer, open them and choose Actions > Send to Customer.io. The message confirms they were sent.
These work whether Send data to Customer.io is on or off. They update people already in Customer.io without duplicating them, don't change anyone's subscription status, and send people only, not past orders or carts.
A sync of all or selected customers runs in the background, and a message tells you when it has finished or failed. Runs are listed on the app's Workflows tab, with their status. Customers that Customer.io refuses are skipped and logged. If the keys are missing or refused, the sync fails before it sends anyone.
Each event has the time it happened in Swell, not the time it was sent, and an ID made from the Swell event's ID. When Swell delivers an event again, Customer.io recognizes the ID and ignores the copy.
If Customer.io doesn't answer within 7 seconds, rate-limits the app, has a server error or refuses the keys, Swell sends the event again later, from a minute to 12 hours apart. An event that still fails after 48 hours is dropped. Customer.io starts campaigns only from events with a timestamp in the last 72 hours.
| Where | What it's for |
| Apps > Customer.io > Settings | The Site ID and API key, the data center, Test connection, and Send data to Customer.io. |
| Apps > Customer.io > Actions | Sync existing customers, which sends every customer. |
| Apps > Customer.io > Workflows | The runs of Sync existing customers and of Send to Customer.io on selected customers, with their status. |
| Customers | Send to Customer.io for the selected customers, and in a customer's Actions menu for that customer. |
| Settings > Notifications | The abandoned cart delay, and Swell's own emails to turn off when Customer.io sends them. |
| Developer > Console > Logs | Each delivery that failed, with Customer.io's reason. |
Settings are in Apps > Customer.io > Settings and are saved separately for each environment.
| Setting | Description | Default |
| Site ID | The Site ID of your workspace's Track API key, from Customer.io > Account Settings > API Credentials. Required. | None |
| API key | The API key of the same Track API key. Masked on the settings page. Required. | None |
| Data center | Read-only. United States or European Union, found from the keys on first use and again when the Site ID changes. | Found on first use |
| Test connection | Checks the saved Site ID and API key with Customer.io and saves the data center. Save the settings first. | |
| Send data to Customer.io | Sends customers and their order, shipment, cart and subscription events as they happen. Events from while it's off aren't sent later. | Off |
| Sync existing customers | In the Actions menu. Sends every customer of the store to Customer.io. |
- Data goes one way. Unsubscribes and other changes made in Customer.io don't reach Swell, so email_optin isn't changed by an unsubscribe in Customer.io.
- Past orders, carts and subscriptions aren't sent as events. Sync existing customers sends people, with their order count, total spent and order dates.
- Customers deleted in Swell stay in Customer.io. The app doesn't delete or suppress people, so delete the person in Customer.io when a customer asks to be erased.
- Partial refunds aren't sent. Order Refunded is sent when an order is fully refunded.
- Carts, orders and subscriptions without a customer aren't sent.
- Subscription Payment Expiring is set up in the app, but Swell doesn't send the subscription event it's based on, so it doesn't arrive.
- Storefront activity, such as page views and products added to the cart, isn't sent. If you add Customer.io's JavaScript snippet to your storefront, identify shoppers by their Swell customer ID so both reach the same person.
- Event and attribute names are fixed.
- Customer.io accepts up to 32 KB per event. If the product list makes an event larger, the list is shortened to fit, and the event has products_truncated set to true.
- Each environment sends to the workspace of the keys entered in it. Test orders reach Customer.io like live ones.
Test connection and the Send to Customer.io actions show their errors in the dashboard. The app also logs each delivery that fails, with Customer.io's reason. In the Swell dashboard, the logs are under Developer > Console > Logs.
Check that Send data to Customer.io is on and saved. It's off after install, and events from while it's off aren't sent later. Click Test connection to check the keys, and check that you're looking at the workspace of the environment you tested in. Cart Abandoned arrives only after Swell marks the cart abandoned, and only for carts with a customer.
The store's admins get this email when Customer.io refuses the Site ID or API key, or when they're missing. Copy both again from Account Settings > API Credentials in Customer.io, paste them in Apps > Customer.io > Settings, save, and click Test connection. Events from the last 48 hours are sent again over the following hours. A successful test closes the problem, so a later one sends a new email. If the subject starts with (TEST), the problem is in the test environment.
Copy the Site ID and API Key of your workspace's Track API key again, and check the key hasn't been deleted in Customer.io. Paste both, click Save settings, then Test connection.
Test connection checks the saved settings. Enter both values and click Save settings before Test connection.
Send to Customer.io needs the Site ID and API key. Enter them in Apps > Customer.io > Settings and save.
Customer.io didn't accept part of the data, and the rest was sent. The reason follows in the log. A message that starts with "Customer.io refused the request" means it refused the whole request. Either way, the event isn't sent again. Fix the cause in Swell, then use Send to Customer.io on the customer to update the person.
Customer.io didn't answer in time, rate-limited the app or had a server error. Swell sends the event again later. If the message came from Test connection, try again in a minute.
The event failed for 48 hours and was dropped. If the customer's details are out of date in Customer.io, use Send to Customer.io on the customer.
The app doesn't unsubscribe customers who haven't opted in. Add the condition email_optin is true to your marketing campaigns and segments.
Set Reference people by to cio_id or id in your Customer.io workspace settings, then use Send to Customer.io on the customer.
The message about the failed run says why. If Customer.io refused the keys, correct them, click Test connection, and run the sync again. Running it again doesn't duplicate anyone.
Uninstalling the app stops sending customers and events to Customer.io, so campaigns triggered by the app's events don't start for new activity. It removes the app's settings, including the Site ID and API key, Sync existing customers, the Send to Customer.io actions and the credentials email. Uninstalling applies to the environment you are in, so remove the app from the test and live environments separately.
The app's delivery issue records are kept and come back if you reinstall. People, attributes and events already in Customer.io stay there. The app isn't notified when it's uninstalled, so if you no longer need the Track API key, delete it in Customer.io under Account Settings > API Credentials.
After a reinstall, enter the keys again and turn on Send data to Customer.io. Changes made while the app was uninstalled aren't sent, so run Sync existing customers to bring people up to date.
| Function | Runs on | What it does |
| sync-customer | account.created and account.updated | Sends the person. Updates that change no field the app sends are skipped. For an emptied field, sends an empty string, and sends unsubscribed when email_optin changed. |
| track-order | order.submitted, order.paid, order.payment_failed, order.delivered, order.refunded and order.canceled | Reads the order with its account and items, and sends the person and the event. |
| track-shipment | shipment.created | Reads the shipment's order, and sends the person and Order Shipped. |
| track-cart | cart.abandoned | Reads the cart, skips it if it has no account, isn't abandoned any more or became an order, and sends the person and Cart Abandoned. |
| track-subscription | subscription.activated, paid, payment_failed, payment_expiring, trial_will_end, paused, resumed, canceled and completed | Reads the subscription with its account and product, and sends the person and the event. |
| test-connection | The Test connection button | Checks the keys, saves the data center and closes an open credentials issue. |
| send-customer | Send to Customer.io on a customer's page | Sends that customer's person. |
| sync-customers | Sync existing customers, and Send to Customer.io on selected customers | A workflow. Checks the keys, then sends customers in id order, 200 per page and 5 pages per step, each step retried up to 4 times. |
The event functions run only while connection.enabled is true in the app's settings, and check it again when they run. The app adds no fields to Swell records. Its settings also hold connection.region and connection.region_site_id, the Site ID the data center was found for.
The app collection apps/customerio/delivery-issues has key, message, source, count, date_last_seen and app_id. A record with key set to credentials exists while Customer.io refuses the keys. Creating it sends the Credentials refused notification to the store's admins. A repeat within 24 hours of date_last_seen updates count, a later one replaces the record and emails again, and Test connection deletes it.
The app calls Customer.io's Track API with Basic authentication, the Site ID and API key, at https://track.customer.io or https://track-eu.customer.io. It finds the region with GET /api/v1/accounts/region on the US host. Each delivery is one POST /api/v2/batch with an identify operation, then an event operation, both identified by { "id": "<Swell account ID>" }:
{
"batch": [
{
"type": "person",
"action": "identify",
"identifiers": { "id": "66e1a7c09b3f2a0012c5d8e4" },
"attributes": {
"email": "maya.chen@example.com", "first_name": "Maya", "last_name": "Chen",
"email_optin": true, "sms_optin": false, "order_count": 12, "order_value": 1486.5,
"last_order_at": 1791794792
}
},
{
"type": "person",
"action": "event",
"identifiers": { "id": "66e1a7c09b3f2a0012c5d8e4" },
"name": "Order Completed",
"id": "01M4QMNHJ0P0Z5M73X009E9F3Y",
"timestamp": 1791794792,
"attributes": {
"order_id": "6acc9e5f3b1d2a0012f4c771", "order_number": "1042", "currency": "USD", "total": 128,
"paid": true, "guest": false,
"products": [{ "product_id": "66e1a7c09b3f2a0012c5d8e5", "name": "Oak Desk Lamp", "price": 89, "quantity": 1 }]
}
}
]
}The event id is a ULID built from the Swell event's ID and the event name, and timestamp is the Swell event's creation time, read from its ID. Requests time out after 7 seconds. Batches stay under 450,000 bytes, and an event over 30,000 bytes has its product list halved until it fits.
A 401 or 403 response, or missing keys, records the credentials issue and fails the delivery with status 401, so Swell retries it. Network errors, timeouts, 408, 429 and 5xx fail it with 503 and are retried. A 207 response with errors, or another 4xx, fails it with 422 and retry: false. A delivery whose $event.delivery.date_first_failed is more than 48 hours old fails with 410 and retry: false.
Swell builds and maintains the Customer.io app. For help with the app, email support@swell.is. For questions about your Customer.io workspace, contact Customer.io.