Summarize this documentation using AI
Overview
When you’re pushing onsite behavior into Customer.io with custom JavaScript, you’re really making a bet on data quality: identity needs to resolve cleanly, events need to fire consistently, and properties need to map the same way every time. If you want a second set of eyes on your tracking plan before you scale cart recovery and repurchase automations, book a strategy call and we’ll pressure-test the data layer like an operator would.
In most retention programs, we’ve seen “JS tracking” succeed or fail based on two things: whether you identify the person at the right moment, and whether the event payloads stay stable enough to build segments and triggers that don’t silently break.
How It Works
Custom JS integrations are simply your site sending people updates and events into Customer.io from the browser. The mechanics matter because the browser is messy: ad blockers, race conditions, and users moving across pages can all create gaps that show up later as “why didn’t this person enter the flow?”
- Data enters as two primitives: people and events. People are profiles (email, phone, attributes). Events are timestamped actions (e.g.,
product_viewed,add_to_cart,email_capture) with properties. - Identity resolution is the whole game. You typically start with an anonymous browser. The moment you capture an email/phone (newsletter form, checkout step, account creation), you should identify the person so subsequent events attach to the right profile. If you wait until “order placed,” your abandonment flows will always be underpowered.
- Event mapping drives segmentation accuracy. Customer.io segments and triggers depend on consistent event names and consistent property types. If
cart_valueis a number on Monday and a string on Tuesday, you’ll end up with segments that look right but don’t match reliably. - Trigger reliability depends on timing and dedupe. Browser events can fire twice (double submits, SPA route changes, back button). If you don’t include a stable idempotency key (like
cart_idorevent_id) in the event payload and dedupe downstream, you’ll accidentally send duplicate recovery messages.
Real D2C scenario: A shopper adds a cleanser to cart, then hits a skin quiz pop-up and submits email for results. If you identify on email capture and send add_to_cart + email_capture with the same cart_id, you can confidently trigger a cart recovery series that also personalizes with quiz outcomes. If you don’t identify until checkout, that same shopper becomes “unknown,” and your highest-intent cart abandoners never enter the journey.
Step-by-Step Setup
Before you write code, align your tracking plan with the retention outcomes you care about (cart recovery, replenishment, winback). Then implement in a way that keeps identity and payloads consistent across every page where intent happens.
- Define your event taxonomy (names + required properties).
Keep it tight:product_viewed,add_to_cart,checkout_started,email_capture,order_placed. For each, define required properties likeproduct_id,sku,price,quantity,cart_id,currency,source. - Pick your identity moments (where you’ll call identify).
Common moments: newsletter/discount pop-up submit, quiz email submit, account creation, checkout email step. Don’t rely on “order placed” if you want abandonment coverage. - Send a person update at identify-time.
When you capture email/phone, update the profile with attributes you’ll actually segment on (e.g.,acquisition_source,quiz_skin_type,sms_consent,first_seen_at). - Send events with stable, typed properties.
Make sure numbers are numbers (not strings), timestamps are consistent, and arrays/objects follow a predictable schema. This is what keeps segments from drifting. - Handle anonymous-to-known stitching.
If you track anonymous browsing events, you need a plan to merge that activity once the user identifies. In practice, this tends to break when identification happens on a different subdomain or after a redirect—test those paths. - Implement dedupe for high-risk events.
Forcheckout_startedandadd_to_cart, include a unique key likecart_id+line_item_id+ timestamp bucket, or your ownevent_id. This prevents double-triggering recovery sequences. - Validate in Customer.io with real sessions.
Use a real browser session to submit a form, add to cart, and start checkout. Confirm: (1) the person profile updates, (2) events appear in the activity feed, (3) event properties look correct and consistent.
When Should You Use This Feature
Custom JS is the right move when the events you need for retention don’t exist in your backend feed yet, or when you need to capture intent earlier than the server ever sees it. It’s especially valuable for onsite forms and micro-conversions that drive identity creation.
- Cart recovery that actually catches anonymous shoppers. Identify on email capture (pop-up, quiz, waitlist) and attach cart events so abandon flows have someone to message.
- Product discovery → repeat purchase loops. Track
product_viewedandcategory_viewedwith clean product metadata so you can segment “viewed X but didn’t buy” and drive a second-session conversion. - Reactivation with better intent signals. Track onsite actions like
back_in_stock_signuporstore_locator_used—these often outperform generic “last seen” logic for winback targeting. - Preference capture that improves LTV. If a shopper tells you “fragrance-free” or “sensitive skin” via a form, send it as a person attribute immediately so future replenishment and cross-sell is relevant.
Operational Considerations
Once this is live, the operational risk isn’t “can we send an event?” It’s whether your segments and triggers stay trustworthy as the site evolves, new forms get added, and your team ships experiments.
- Segmentation depends on schema discipline. Lock required properties for key events (cart, checkout, purchase). If your theme/app changes rename
productIdtoproduct_id, your segments quietly degrade. - Identity collisions happen. Shared devices, forwarded links, and multiple emails per browser session can attach events to the wrong profile if you identify too aggressively. Decide rules: when to re-identify, when to treat as a new person, and how to handle logout.
- Browser delivery is not guaranteed. Ad blockers and script failures will create missing events. For revenue-critical events (orders), rely on server-side sources where possible, and use JS for intent and form capture.
- Orchestration reality: triggers need guardrails. If
add_to_cartfires multiple times, your journey needs frequency controls and/or event dedupe logic, otherwise you’ll spam high-intent shoppers and hurt deliverability. - Debugging needs a repeatable workflow. Keep a QA checklist and a test profile. Every time you ship a new onsite experience (quiz, pop-up, bundle builder), re-validate identity + event payloads.
Implementation Checklist
If you want this to hold up after the first few experiments and theme changes, treat tracking like a product surface: documented, tested, and owned.
- Event taxonomy defined (names, required properties, property types)
- Identity plan documented (where/when identify happens, re-identify rules)
- Person attribute map defined (what goes on the profile vs what stays event-level)
- Dedupe strategy for high-risk events (cart/checkout/form submits)
- QA paths tested: anonymous browse → email capture → cart → checkout start
- Customer.io activity feed validated for payload consistency
- Segments built off “required properties only” for critical journeys
- Fallback plan for blocked JS (server-side purchase events, conservative triggers)
Expert Implementation Tips
The difference between “we track events” and “we can run retention off this confidently” is usually a handful of operator habits.
- Make
cart_idnon-negotiable. If you want accurate cart recovery, every cart-related event should carry the samecart_id. It becomes your stitching key across sessions and channels. - Capture email before checkout whenever possible. A simple “save your cart” or “get 10% off” capture can double the addressable abandonment pool—assuming you identify and attach cart events immediately.
- Keep event names boring and durable. Don’t name events after experiments (
quiz_v3_submit). Use stable names (quiz_completed) and pass versioning in properties. - Prefer person attributes for slow-changing truths. Skin type, pet owner, subscription preference—store on the profile. For fast-changing state (cart contents), keep it event-level to avoid overwriting useful history.
- Build “data quality segments.” Create internal segments like “Add to cart missing cart_id” or “Checkout started missing email” so you can spot breakage before revenue does.
Common Mistakes to Avoid
Most issues don’t show up as obvious errors. They show up as underperforming flows and the team blaming creative—when it’s actually data.
- Identifying too late. If you only identify at purchase, you’ve basically opted out of abandonment and browse recovery.
- Changing property names/types without a migration plan. This breaks segments and journey conditions in ways that are hard to notice until performance drops.
- Over-sending events. Tracking every click creates noise and makes segmentation harder. Track intent moments that map to retention actions.
- No dedupe on form submits. Double submits lead to duplicate welcome offers, duplicate cart messages, and support tickets.
- Mixing anonymous and known data without clear stitching. You end up with two profiles per shopper and “missing” activity in the profile your journeys actually target.
Summary
If you need earlier intent signals and better identity capture, custom JS integrations are worth it—but only if you treat event schema and identity as first-class. Get those right and your segments stay accurate, your triggers fire reliably, and your retention automations stop leaking revenue.
Implement Javascript Form Integrations with Propel
If your highest-leverage identity moments happen in onsite forms (pop-ups, quizzes, waitlists, bundle builders), it’s worth implementing them in a way that won’t break the next time your theme or apps change. We’ll typically start by auditing what’s entering Customer.io, then tightening identity resolution and event payloads so your cart recovery and winback triggers behave predictably. If you want that kind of operator-level tracking plan and QA process, book a strategy call.