Skip to main content

Documentation Index

Fetch the complete documentation index at: https://documentation.onesignal.com/llms.txt

Use this file to discover all available pages before exploring further.

An ecommerce messaging strategy targets sites and apps where success depends on conversion of browsers to buyers, repeat purchase frequency, and customer lifetime value. If you sell products online — direct-to-consumer, marketplace, or subscription commerce — this guide is for you. This page is the implementation hub: which customer identifier to set, what browse and purchase data to capture, which segments to build, and which Journeys drive cart recovery, post-purchase engagement, and win-back. Each section links to the canonical docs for deeper detail.
If you run on Shopify, the Vendo integration automatically syncs the customer Tags and Custom Events recommended below. You can complete the data foundation in this guide with one-click setup instead of manual instrumentation.

Implementation roadmap

Work through these steps in order. Each one links to its section below.
1

Assign External IDs

Set a stable customer identifier on every authenticated shopper so push, email, and SMS tie to one profile across reinstalls and devices. Jump to section.
2

Add customer properties as Tags

Start with customer_status, total_spend_cents, and last_purchase_date. These three power every RFM (recency, frequency, monetary) segment. Jump to section.
3

Send shopper actions as Custom Events

Fire product_viewed, product_added_to_cart, checkout_started, and checkout_completed from your storefront or backend. Jump to section.
4

Build lifecycle Segments

Customer audiences such as Cart abandoners, First-time buyers, Repeat customers, VIPs, and Lapsed customers. Jump to section.
5

Create lifecycle Journeys

Welcome, cart recovery, post-purchase, loyalty, and win-back. Jump to section.

Identify your customers with External IDs

External IDs preserve identity across installs and tie push, email, and SMS to one customer profile. Use the unique identifier from your commerce platform — for example, your Shopify Customer ID, an Auth0 uid, or your internal customer_id. Set the External ID at signup, on every login, on order placement, and on session resume. The OneSignal SDK does not assign it for you, and assigning it late or sporadically breaks attribution between browse activity, cart events, and downstream purchases — making conversion and retention analytics unreliable. For anonymous shoppers (the majority of ecommerce traffic), the OneSignal-assigned anonymous user ID still ties Tags and behavior to a Subscription. Promote anonymous profiles to authenticated profiles by setting the External ID the moment a shopper logs in or completes checkout — that single call merges the anonymous browse history with the new identity.

External ID setup

Assign a unique customer identifier so browse history, cart state, and notifications follow the customer across devices.
Tags persist on the customer profile (current state); Custom Events record discrete moments (what just happened). Use both — Tags drive RFM segmentation and personalization, Custom Events trigger Journey entry and Wait Until conditions. Ecommerce leans heavily on Custom Events because most lifecycle moments are behavioral: a product view, a cart add, a checkout start, a purchase. Tags capture the resulting state — total spend, purchase count, customer tier — which Journeys filter on for loyalty and retention messaging.

Tags

Tags persist on the customer profile and are used for segmentation and personalization. For boolean-style signals, set the Tag to 1 when true and remove it when false — segment with “tag exists” rather than storing 0/false values.
If you only set up four Tags, start with customer_status, total_spend_cents, last_purchase_date, and first_name. They power every RFM-based Journey.

Customer lifecycle and value

TagValuesUse
customer_statusprospect / first_time_buyer / repeat_customer / vip / lapsedLifecycle state — drives Journey entry, exit, and audience filters.
loyalty_tierbronze / silver / gold / platinum (your tiers)Tailor offers, perks, and exclusivity by tier.
total_spend_centsinteger (as string)Lifetime value. Powers VIP and high-spender segments.
purchase_countinteger (as string)Frequency signal. Combine with total_spend_cents and last_purchase_date for RFM scoring.
last_purchase_dateUnix timestamp (seconds)Recency. Use time operators to send win-back offers a fixed number of days after the last order.

Browse and cart

TagValuesUse
cart_value_centsinteger (as string)Current cart subtotal. Personalize cart-recovery copy with the actual value at risk.
cart_item_countinteger (as string)Number of items in the active cart. Useful for “you have N items waiting” messaging.
wishlist_countinteger (as string)Engagement signal. Wishlist activity often outperforms cart adds as a purchase predictor.
favorite_categorystring (e.g., apparel, home, beauty)Single most-shopped category. Personalize subject lines, push copy, and product recommendations.
cat_<category>1 (set when shopped)One Tag per category for stores with broad catalogs (e.g., cat_apparel, cat_home, cat_beauty). Use when shoppers regularly buy across multiple categories — favorite_category alone can’t express multi-interest. Set automatically from product_viewed or purchase_completed events.

Subscription commerce (subscribe-and-save)

Use these Tags only if you offer subscribe-and-save, replenishment, or other recurring-shipment programs. Skip the subsection for one-time-purchase stores.
TagValuesUse
subscribe_save_active1 (set when an active subscription exists)Lifecycle filter for subscription-aware messaging; suppress one-off promotions for the same SKU.
next_replenishment_dateUnix timestamp (seconds)Drive pre-shipment reminders (“ships in 3 days”) and skip-window outreach. Pair with time operators.
replenishment_cadence_daysinteger (as string, e.g., 30, 60, 90)Personalize copy with the customer’s chosen cadence and detect cadence-mismatched usage.

Personalization and source

TagValuesUse
first_namestringPersonalize message content (e.g., Hi {{ first_name | default: 'there' }}).
preferred_localestring (e.g., en-US, fr-CA)Drive locale-aware content and localized message variants.
email_signup_sourcepopup / checkout / account / referralWhere the customer entered their email (form they filled). Tailor welcome copy to the surface that captured the address.
acquisition_sourcepaid_social / organic / referral / directFirst-touch channel that brought the customer to your store. Tune onboarding to the acquisition channel — distinct from email_signup_source which is the on-site capture point.

Add user data tags

Add key-value pairs to customer profiles for segmentation and personalization.

Custom Events

Send a Custom Event for each shopper action you want to react to. Events are stored shorter-term than Tags but can carry properties (product ID, variant, price, currency, cart contents), making them ideal for Journey entry triggers, Wait Until conditions, and Liquid personalization. Use lowercase snake_case for event names and keep them consistent across your storefront, backend, and any platform integrations. The events below match the ones the Shopify Vendo integration sends automatically — align with these names even on custom storefronts so your Journeys port cleanly between platforms.
EventUse case
signup_completedWelcome Journey entry.
product_viewedBrowse-abandonment Journey entry; build behavioral interest profile via properties.
collection_viewedCategory-level interest signal.
search_submittedIntent signal — surface relevant products in next session.
product_added_to_cartCart-recovery Journey priming step.
product_removed_from_cartDown-weight cart urgency or exit a cart Journey for that product.
cart_viewedActive-shopping signal; useful as a Wait Until anchor.
checkout_startedCart-recovery Journey entry. Pair with a Wait Until on checkout_completed to detect abandonment.
checkout_completed / purchase_completedExit cart-recovery Journey; trigger post-purchase Journey. Carries order ID, total, and items.
payment_failedDeclined-card recovery Journey entry. Carry failure_reason (e.g., card_declined, insufficient_funds) as a property for tailored copy and a quick retry path.
order_shipped / order_deliveredTransactional updates — send via the Transactional messages API.
refund_requested / return_initiatedService-recovery Journey trigger; suppress upsell and review-request copy while the return is open.
review_submittedPost-purchase satisfaction signal; use to gate referral and UGC asks.
loyalty_points_earnedUpdate progress messaging (“250 points to next reward”). Carry points and running_balance as properties.
loyalty_tier_upgradedTier-celebration Journey entry. Carry previous_tier and new_tier as properties for personalized copy.
back_in_stockBackend-fired event that triggers a wishlist-targeted alert Journey.
price_dropBackend-fired event mirroring back_in_stock. Targets customers with the product on their wishlist or recently viewed. Carry product_id, old_price, and new_price as properties.
subscribe_save_started(Subscription commerce only.) Onboarding Journey entry for new subscribe-and-save customers.
replenishment_skipped(Subscription commerce only.) Churn-risk signal — trigger a save Journey before the next billing date.
replenishment_processed(Subscription commerce only.) Confirm shipment, surface upsells for complementary SKUs, and reset the cadence-reminder Journey.
subscribe_save_cancelled(Subscription commerce only.) Win-back Journey entry — separate from one-off subscription_cancelled flows.

Custom Events

Capture shopper actions and use them to trigger Journeys or Wait Until steps.

Segments

Combine Tags and Custom Events into segments. Start with these ten:
SegmentDefinition
New visitorsFirst Session < 7 days ago AND purchase_count does not exist. Welcome and first-purchase target.
Cart abandonerscheckout_started in the last 24 hours AND checkout_completed does not exist in the same window. Highest-leverage recovery segment.
Browsers (no purchase)product_viewed in the last 30 days AND purchase_count does not exist. Long-tail conversion target.
First-time buyerspurchase_count = "1". Onboarding into the loyalty Journey, second-purchase incentive target.
Repeat customerspurchase_count > 1. Cross-sell and category-expansion target.
High-frequency loyalistspurchase_count >= 5 in the last 90 days. Surfaces frequent shoppers at lower price points (consumables, beauty, replenishment categories) — distinct from spend-based VIPs.
VIPs / High-spenderscustomer_status = "vip" OR total_spend_cents > 50000 (your threshold in cents). Premium offer audience.
At-risk repeat customerspurchase_count > 1 AND last_purchase_date between 30 and 60 days ago. Catches early signs of lapse before the 90-day Lapsed bucket — win-back copy lands much better at 45 days than at 90.
Lapsed customerslast_purchase_date > 90 days ago AND customer_status != "vip". Win-back audience.
Wishlist holderswishlist_count > 0. High-intent for back-in-stock and price-drop alerts.
Mature ecommerce setups run 30+ segments split by category, geography, loyalty tier, channel, and seasonality. Start with the ten above plus a segment per top-level category, then add depth (predicted LTV bucket, return-rate cohort, last-channel-clicked) as your Journeys grow.

Segmentation

Group customers by shared characteristics to target Journeys and campaigns.

Journey examples

With Tags, Custom Events, and segments in place, build Journeys against them. Ecommerce Journeys mix channels by intent — push and in-app for time-sensitive nudges (cart recovery, back-in-stock, flash sales), email for receipts, recommendations, and longer-form recovery, and SMS for high-value moments like VIP launches and order updates. The lifecycle has six core flows:

Welcome and first purchase

Drive a new shopper from signup to their first checkout with a graduated nudge cadence.

Abandoned cart recovery

End-to-end Wait Until tutorial for checkout_startedcheckout_completed recovery.

Post-purchase and cross-sell

Receipt, shipping updates, review request, and timed cross-sell on purchase_completed.

Loyalty and tier upgrades

Reward tier transitions and milestone purchases with VIP-only offers.

Win-back for lapsed customers

Re-engage shoppers who haven’t purchased in 90+ days with category-aware comeback offers.

Back-in-stock and price-drop alerts

Backend-fired back_in_stock events targeted to customers with the matching wishlist Tag.

Common ecommerce patterns

  • Cart recovery is the highest-leverage Journey. Most cart abandoners still intend to purchase — they just need a reminder. Build a Wait Until on checkout_completed after checkout_started, with a 30-minute first-touch and a 24-hour follow-up. See the Abandoned cart tutorial for the full implementation.
  • Personalize with cart contents using Liquid. Cart-recovery and browse-abandonment messages pull dramatically higher CTR when they reference the actual product. Use Custom Event personalization to inject {{ product_name }} and {{ product_image_url }} from the product_added_to_cart event payload — see Liquid syntax.
  • Treat post-purchase as both transactional and marketing. Order confirmations, shipping updates, and delivery alerts are transactional — send via the Transactional messages API so they bypass marketing-consent gates. Cross-sell, review requests, and refill prompts are marketing — send through standard Journeys with marketing-consent filters.
  • RFM-based win-back, not blanket discounts. A 90-day-lapsed VIP needs different copy and incentive than a 90-day-lapsed first-time buyer. Build separate win-back Journeys per customer_status × loyalty_tier cell so your highest-LTV customers don’t get the same 10%-off email as a one-time clearance shopper.
  • Wishlist + back-in-stock is an underused loop. Track wishlist additions as a Tag (wishlist_count) and per-product Custom Events. When inventory returns, fire back_in_stock from your backend with the product_id as a property and target only the customers with that product on their wishlist. Conversion rates are often the highest in your messaging program.
  • Quiet hours and frequency caps matter more in ecommerce. Promotional fatigue compounds fast. Apply Journey-level frequency caps (e.g., at most one promo push per 24 hours per customer) and use Time Window to keep sends inside reasonable hours in the customer’s local timezone.
Measure success by cart-recovery rate (checkout_completed after checkout_started), repeat-purchase rate at 30 / 60 / 90 days, average order value (AOV) trend, and 90-day customer LTV — not just opens or CTR.

FAQ

How is this different from the Mobile-first strategy?

Mobile-first targets subscription, freemium, and trial-driven apps where success is measured by trial-to-paid conversion. Ecommerce overlaps on the data foundation (External IDs, Tags, Custom Events, segments) but the conversion moment is a transaction (or repeat transaction), not a trial flip. The lifecycle is shaped around RFM segmentation and Wait-Until-based recovery flows rather than time-based trial sequences.

Should I use a Tag or a Custom Event for cart state?

Use Custom Events for cart actions (product_added_to_cart, checkout_started, checkout_completed) — they carry the cart contents and are the right fit for Journey entry and Wait Until conditions. Use a Tag (cart_value_cents, cart_item_count) for the resulting state when you want to personalize copy with the current cart total or filter segments by cart presence. Both work together.

How do I prevent cart-recovery messages from sending after a purchase?

Use a Wait Until step on checkout_completed with Event Matching on a shared property like cart_id or customer_id — the event branch fires the moment the same customer completes the matching cart, exiting them from the recovery Journey before any reminder sends. The Abandoned cart tutorial shows the full configuration.

How long should my cart-recovery window be?

A 30-minute first touch and a 24-hour follow-up convert most recoverable carts. Push past 48 hours and you’re generally wasting opt-in — abandoners who haven’t returned by then either bought elsewhere or weren’t ready to buy. Stage the cadence by channel: push or in-app for the first nudge (lowest friction), email for the 24-hour follow-up (more space to surface the cart contents and recommendations), and SMS only for high-value carts where you have explicit consent.

How do I handle returned and refunded orders in segmentation?

Decrement total_spend_cents and purchase_count on refund_processed, or maintain a parallel lifetime_spend_net_cents Tag if you want gross spend for analytics and net spend for segmentation. Without this, a customer with one 500returnregistersasarepeat500 return registers as a repeat 500 customer who will never buy again — they pollute Lapsed and VIP segments. Also fire refund_requested to suppress upsell and review-request copy while the return is open.

What about sending transactional order updates?

Order confirmations, shipping notices, and delivery updates should send via the Transactional messages API — these are time-sensitive, don’t require marketing consent, and shouldn’t be subject to marketing-frequency caps. Keep them separate from your promotional Journey infrastructure.

Can I run this without a Shopify or commerce-platform integration?

Yes. The Custom Events and Tags APIs accept the same data from any storefront — custom builds, headless commerce, or other platforms. The Vendo Shopify integration automates the wiring; for other platforms, instrument the events listed above on your storefront and order-management system.

How do I handle international stores with different currencies?

Track money values in the smallest unit of a single base currency in total_spend_cents and cart_value_cents (typically USD cents) and convert at display time using a preferred_locale or currency_code Tag. This keeps RFM segmentation consistent across regions while letting Liquid personalization render the localized currency in copy.

How does this guide work for subscribe-and-save and replenishment commerce?

Use the ecommerce Tags and events as the foundation, plus the Subscription commerce Tags (subscribe_save_active, next_replenishment_date, replenishment_cadence_days) and events (subscribe_save_started, replenishment_skipped, replenishment_processed, subscribe_save_cancelled) listed above. Subscription messaging blends ecommerce patterns (cart, browse, post-purchase) with mobile-first patterns (renewal reminders, churn-risk Journeys) — see Mobile-first strategies for the recurring-revenue side, especially the renewal-window and at-risk subscriber Journeys.

Abandoned cart tutorial

End-to-end Wait Until Journey for checkout_startedcheckout_completed recovery.

Shopify integration

Vendo integration that auto-syncs the customer Tags and Custom Events recommended in this guide.

Mobile-first lifecycle Journeys

Welcome and retention Journey patterns adaptable to ecommerce onboarding and win-back.

Event-driven Journeys

Trigger Journeys from purchase_completed, back_in_stock, and other commerce events.

Transactional messages

Send order receipts, shipping updates, and delivery alerts through the API.

Personalization with Custom Events

Inject product names, images, and prices into messages from event payloads.