Summarize this documentation using AI
Overview
If your retention automations feel “random” (some carts recover, others never enter the flow), it’s usually not the creative—it’s tracking. This guide breaks down how to troubleshoot SDK-side issues so Customer.io receives the right identities and events at the right time. If you want a second set of operator eyes on your instrumentation and triggers, book a strategy call and we’ll walk through what’s breaking and how to fix it.
In most retention programs, we’ve seen “missing revenue” come from three root causes: users never get identified, events fire with the wrong payload, or events arrive out of order (so your Journey conditions don’t match).
How It Works
When you send events from your mobile/web app via the Customer.io SDK, Customer.io ties those events to a person profile. That sounds simple, but in practice it tends to break at the exact points retention depends on: the handoff from anonymous browsing to known identity, and the moment you need a clean event (like Added to Cart) to trigger a cart recovery Journey.
- Identity stitching is the foundation. The SDK needs a stable identifier (typically your internal user ID) via an
identifycall. If you only rely on email, or you identify too late, you’ll see “anonymous activity” that never qualifies for your segments and triggers. - Events must be consistent and complete. Your Journey logic is only as good as the event name + properties you send. If one client sends
add_to_cartand another sendsAdded To Cart, you’ve effectively created two different triggers. - Ordering and timing matter. If
Added to Cartfires beforeidentify, the event may attach to an anonymous profile. If your Journey expects a known user (email/push eligible), they won’t enter. - Device context affects channel eligibility. Push requires a valid device token tied to the same identified profile. If tokens sit on an anonymous profile while the user ID lives elsewhere, push audiences look smaller than they should.
Step-by-Step Setup
Troubleshooting goes faster when you work from the app outward: confirm SDK initialization, then identity, then events, then Journey entry. Don’t start by tweaking the Journey—prove the data is arriving correctly first.
- Confirm SDK initialization in the app
- Verify the SDK is initialized once, early in app launch (and not re-initialized on every screen).
- Check environment separation (dev/staging/prod). A classic issue: QA tests in staging while Journeys listen in prod.
- Verify your
identifystrategy (when and with what ID)- Identify immediately after login/account creation, using a stable internal user ID (not email as the primary key).
- Send email/phone as attributes, but don’t use them as the only identity anchor—people change emails, and you’ll create duplicates.
- If you support guest checkout or browse-to-buy flows, decide how you’ll bridge anonymous activity into a known profile (e.g., identify at email capture, or at checkout start).
- Audit event naming and required properties
- Pick one canonical event name per behavior (e.g.,
added_to_cart,checkout_started,order_completed). - Standardize properties needed for segmentation and personalization:
sku,product_id,category,price,currency,quantity,cart_value. - Make sure values are typed consistently (numbers as numbers, timestamps as timestamps). “12.00” as a string breaks numeric comparisons later.
- Pick one canonical event name per behavior (e.g.,
- Validate event order around identity
- Ensure
identifyoccurs before key retention triggers whenever possible. - If that’s not possible (e.g., you want to track pre-login browsing), plan to merge anonymous activity into the identified profile and confirm it’s actually happening in your setup.
- Ensure
- Test in a real device session and trace one user end-to-end
- Create a test user, perform: view product → add to cart → abandon → return → purchase.
- In Customer.io, pull up that person profile and confirm: attributes updated, events present, device token present (for push), and timestamps make sense.
- Only then validate Journey triggers and filters
- Confirm the Journey listens to the exact event name and property keys you’re sending.
- Check filters like “within the past X minutes/hours” and make sure your event timestamps align with your expected timezone/format.
When Should You Use This Feature
SDK troubleshooting isn’t a “nice to have.” If you’re running retention on behavioral triggers, you need instrumentation you can trust—otherwise you’ll keep patching symptoms in messaging while the data stays broken.
- Cart abandonment recovery (mobile-heavy brands). If your app drives most sessions, missing
added_to_cartevents or lateidentifycalls will quietly cut your recovery volume. - Post-purchase replenishment. If
order_completedsometimes fires without line items, you can’t segment by product purchased, which kills cross-sell and replenishment accuracy. - Reactivation after churn signals. If you’re using “last viewed category” or “last app open” logic, inconsistent event payloads will misclassify customers and waste sends.
- Push-first orchestration. If device tokens aren’t reliably tied to the identified profile, your push audience shrinks and your flows default to email—even when the customer is active in-app.
Real scenario: A skincare D2C brand sees iOS cart recovery underperforming. Email sends look fine, but conversion is low. The root cause ends up being identity: iOS users add to cart while anonymous, then log in at checkout. The added_to_cart event stays on an anonymous profile, so the cart Journey never triggers for known users. Fix: move identify earlier (email capture) and confirm anonymous activity merges correctly.
Operational Considerations
Once the SDK sends clean data, the next problems are operational: how you segment, how you handle duplicates, and how you orchestrate across channels without fighting your own data model.
- Segmentation depends on property hygiene. If you plan to segment “cart value > $75” or “viewed category = running,” you need consistent property keys and types across iOS/Android/web.
- Duplicate people will poison holdouts and frequency caps. When identity isn’t stable, one shopper becomes two profiles. That leads to double-sends, broken suppression logic, and misleading reporting.
- Event volume and noise matter. Don’t track every UI interaction. Track the behaviors that map to retention decisions (viewed product, added to cart, checkout started, purchased, subscribed, refunded).
- Orchestration reality: “near real-time” still has edges. If you trigger a Journey instantly on
checkout_startedbut theorder_completedevent arrives seconds later, you need exit conditions that prevent sending a recovery message to someone who already purchased. - Cross-platform consistency is non-negotiable. Your web team and mobile team must share the same event contract. Otherwise, your segments become platform-specific without you realizing it.
Implementation Checklist
Use this as a pre-flight before you trust any retention KPI that depends on SDK events.
- SDK initialized once per app session, in the correct environment (prod vs staging)
identifyfires reliably with a stable internal user ID- Email/phone stored as attributes (not used as the only identifier)
- Anonymous-to-known stitching strategy defined and verified with a real test session
- Canonical event names agreed across iOS/Android/web
- Required properties present for key events (cart, checkout, purchase)
- Property types consistent (numbers, strings, timestamps)
- Device tokens attached to the identified profile (push eligibility matches expectations)
- Journey triggers match exact event names and keys
- Exit conditions prevent post-purchase “recovery” messages
Expert Implementation Tips
These are the small operator moves that keep your program stable as you scale channels, products, and platforms.
- Write an “event contract” doc and enforce it. One page: event names, required properties, optional properties, examples. Treat it like an API.
- Track a single cart identifier. Include a
cart_idon cart/checkout events. It makes deduping and debugging dramatically easier. - Send both item-level and summary fields. Keep
items(array) for personalization, but also sendcart_valueanditem_countfor fast segmentation. - Build “debug segments” in Customer.io. For example: “Has added_to_cart in last 30 minutes AND has email.” If that segment is smaller than expected, you know it’s identity, not creative.
- Protect against double-firing. Mobile apps often fire events twice (screen re-render, back/forward navigation). Add client-side guards or server-side dedupe logic where possible.
Common Mistakes to Avoid
Most issues show up as “Customer.io isn’t sending,” but the real problem is upstream. These are the patterns we see repeatedly in D2C apps.
- Identifying only at purchase. Great for attribution, terrible for cart recovery and browse abandonment because you miss the window.
- Using email as the primary identifier. It increases duplicates and breaks stitching when users update emails or use Apple Hide My Email.
- Inconsistent event names across platforms. Your Journey listens to one string. Slight differences silently drop users.
- Missing required properties for segmentation. If you don’t send
categoryorsku, you can’t do product-aware retention—everything becomes generic. - No purchase-based exit condition. You end up sending “Complete your order” after the order completes, which trains customers to ignore you.
- Testing only in simulators. Push tokens, deep links, and real-world app state behave differently on actual devices.
Summary
If cart recovery and repeat purchase flows feel inconsistent, assume a tracking/identity issue until proven otherwise. Get identify right, standardize event names/properties, then validate Journey logic. Once data is clean, optimization actually sticks.
Implement Troubleshooting with Propel
If you’re seeing gaps between on-site/app behavior and who actually enters Journeys, it’s worth doing a structured audit: identity stitching, event contracts, and channel eligibility. We’ll help you trace a single customer session end-to-end in Customer.io, pinpoint where the data breaks, and tighten the instrumentation so your retention automations trigger reliably. If that’s useful, book a strategy call and we’ll map fixes to the flows that drive revenue first.