Where the decision starts
Immediately after payment, a customer receives “you still have items in your cart.” They wonder whether the order failed, while the CRM owner asks why a buyer-exclusion rule did not stop the message. This is a design example illustrating an incorrect-send mechanism.
First distinguish eligibility to enter a Journey from eligibility to receive a message now. Being a nonbuyer when creating a cart does not imply remaining one after a wait. Investigate delayed purchase propagation, mismatched customer/business references and duplicate events restarting a Journey separately. OneSignal permits concurrent entry in event-based Journeys, while Shopify does not guarantee webhook order. A setting named “exclude buyers” does not resolve these conditions by itself.[1][5]
Start by defining purchase completion, which cart reminder ends and when state is checked again. Then connect platform exits/branches to the application's sending decision. However, a last-minute query does not make the external order and messaging systems commit as one transaction. Define where prevention remains possible and where transmission may already have occurred.
Purchase completion and the time to stop a reminder can differ
In Shopify Classic Webhooks, orders/create means order creation and orders/paid means an order was paid. Current financial states separately include PENDING, AUTHORIZED and PAID. PAID includes automatic/manual capture and orders an administrator marked paid. A payment-button click or order creation alone is not evidence that funds processing completed.[3][4]
Yet cart reminders need not continue until payment completion. Telling someone “you have not purchased” can be inappropriate even while their accepted order is still being paid.
This design example chooses the following policy for logged-in customers placing prepaid online orders. Adjust it to actual payment methods and customer-service policy; it is not default Shopify or OneSignal behavior.
- Hold reminders once an order is created from that cart or payment is in progress. End existing reminders for that cart when purchase completion is confirmed.
- Hold if order/customer/cart relationships or current state cannot be verified; do not classify uncertainty as nonpurchase.
- Do not revive an ended cart reminder after cancellation, partial refund or full refund. Evaluate new carts and repurchase campaigns separately.
Shopify also distinguishes orders/cancelled from refunds/create. In particular, refunds/create concerns creation of a refund record independently of actual funds movement. It provides no basis for interpreting the customer as a nonbuyer again or newly eligible for advertising.[3]
Record the decision unit. Customer U purchasing cart C1 does not mean their new cart C2 is complete. Use the service's customer–cart–order relationship, rather than one customer-level purchased=true/false, to determine which reminder ended. Where mapping is impossible, hold that customer's reminders instead of guessing.
Messages connected to customer behavior — Use lifecycle stages and behavior to connect channels and timing, then refine journeys through experiments.
Sending can occur between purchase and CRM propagation
The following hypothetical timeline schedules a decision on cart C1 at 10:30. It is neither measured latency nor a product processing guarantee.
| Time | Event | Distinction to retain |
|---|---|---|
| 10:00:00 | Create C1 reminder candidate and begin waiting | Entry reason and cart identifier |
| 10:29:58 | Order source records C1's completed purchase | Business-event occurrence time |
| 10:30:00 | Sending job runs before purchase appears in CRM | Decision time and state version read |
| 10:30:01 | Messaging provider accepts a request allowed by stale state and begins transmission | Acceptance/transmission times and message ID |
| 10:30:02 | Purchase webhook reaches the application | Webhook receipt time |
| 10:30:03 | Application saves C1 as excluded | Internal eligibility update time |
| 10:30:05 | Exit state/event reaches the messaging platform | Platform propagation and evidence of actual Journey exit |
Exiting the Journey on the last line does not undo an earlier transmission. OneSignal's Cancel message API stops scheduled or ongoing sends, but explicitly notes that cancellation after sending starts may not prevent all recipients from receiving it.[10]
If the 10:30 job reread the order source and saw the purchase, it could avoid creating the request. A smaller race remains if purchase occurs after that query but just before handoff to the provider. One extra query does not establish zero post-purchase incorrect sends.
Keep purchase occurrence, webhook receipt, internal update and platform update as separate times. Check source timestamp semantics and clock differences; leave unavailable times unknown. These fields are not automatically present in every platform's logs. Distinguish existing evidence from additional instrumentation.
What to configure in OneSignal and what to decide separately
Official documentation checked on September 26, 2026 describes the following controls. Focus on the data each control reads and where it applies, rather than its name.
| Required control | Official feature and scope | Work remaining in application/operations policy |
|---|---|---|
| Entry, exit and reentry | Enter through a segment or Custom Event. General Re-entry rules apply to segment Journeys; event Journeys allow reentry.[1] | Distinguish duplicate entry for one event from legitimate entry for a new cart |
| Reevaluate after waiting | Wait delays time; Wait Until waits for a condition; Yes/No branches on segment membership or message behavior.[2] | Elapsed time is not evidence of nonpurchase; define the timeout path |
| Match completion to the same business item | Event-triggered Wait Until provides Event Matching between starting and waiting-event properties.[2] | Connect values so C1 completion does not end C2's reminder; do not assume every Exit rule provides per-item matching |
| Conflicts with other Journeys | Tags/exclusion segments can coordinate membership.[1][2] | Do not treat tags read concurrently by several Journeys as an atomic lock |
Sources: OneSignal Journey settings and Journey actions.[1][2]
Specifically test already-purchased customers satisfying both entry and exit conditions. OneSignal notes that the first step can execute before exit and recommends an initial wait or explicit exclusions for segment entry. Do not assume event and segment entry can be combined in the same entry rule.[1]
The official abandoned-cart tutorial uses cart_updated for both entry and exit to restart with current cart contents. Reentry filters and empty-cart handling must still be correct. This pattern alone does not resolve an old cart update arriving after purchase.[12]
For strict exclusions, decide where the sending request is created
If the problem is an incorrect purchase exit, first step or identifier mapping in an existing Journey, correct that configuration first. Not every service needs a separate sending system.
When orders span several systems or events repeatedly arrive late, and some valid sends may be sacrificed to reduce incorrect reminders, consider application ownership of the final sending request. The following is a proposed implementation direction.
Candidate → authoritative order source or verified current state → customer/cart mapping → consent/subscription/deduplication/frequency checks → authorization record → messaging API request
Exclude in-progress or completed orders; hold failed queries or unclear mappings. Record decision time, evidence state, campaign configuration version, selected channel and recipient. Reevaluate jobs that waited in a queue before execution. If this stage moves into the application, assign one sending owner so the existing Journey message step does not independently send.
Test two jobs simultaneously reading “not sent yet.” Use uniqueness constraints and transactions to check and reserve sending rights for the customer/cart/reminder step atomically. Retries reuse the existing authorization record and request key rather than creating new ones. This coordinates your own sending jobs; it does not lock purchases in an external order system.
Adding a Journey webhook before a message does not complete this design. Its documented function sends an HTTP request to an external server. Documentation does not establish atomicity between its response, the next message step and the order source. Journey webhooks also have separate access conditions. The gate described here is a separate design using an application queue/scheduler and messaging API, not an automatic Journey property.[13]
The race between the final query and external transmission remains. Detect payment in progress earlier, reduce queue delays and decline to send when state is uncertain to reduce it. Without one transaction spanning external Shopify and OneSignal, do not promise to prevent every receipt after actual purchase time. Operational rules should state both that no request is created when the final check confirms purchase and that already-handed-off requests may not be fully cancelable.
Connect the data each campaign needs — Define events and attributes from campaign needs, then align identifiers, transmission timing and measurement tools.
Deduplication, frequency caps and identity are separate problems
Shopify webhooks may arrive out of order or more than once, and delivery is not always assured. Official guidance recommends periodic source reconciliation to recover missing events. Prevent a late “cart exists” event from reversing a confirmed purchase exit, and recover missing purchases through source queries.[5][6]
Deduplicate receipt and sending separately. Shopify X-Shopify-Webhook-Id identifies duplicate deliveries; X-Shopify-Event-Id connects deliveries from the same shop action. Separately retain sending records for the customer/cart/reminder step. Event deduplication alone does not prevent another Journey from creating a message for the same purpose.[6]
Retry the OneSignal messaging API with the same logical request's idempotency_key. Notification creation keys are retained for 30 days. Custom Events deduplication is instead best effort within four hours, not permanent strict event deduplication. Neither mechanism decides whether sending to this customer is appropriate now.[7][8]
Frequency capping reduces overmessaging. OneSignal's feature applies to push, not one combined limit across email, SMS and in-app messages. Capped pushes are discarded rather than queued for later sending. Design purchase eligibility and cross-channel priorities separately.[9]
For one customer across devices, base eligibility on the service customer ID, but one sending decision and receipt on one device are different conditions. Sending to only one device also requires a recipient-selection rule. Check logout on shared devices: OneSignal mobile SDK logout() detaches the current mobile subscription from its user without logging out all other subscriptions.[11]
Do not assume logout removes exposure from notifications already handed off. Avoid unnecessary purchase data on lock screens and recheck the currently logged-in account's cart authorization when opening a notification link. Check channel subscriptions and service-managed marketing consent independently. Do not automatically route around an opt-out through another channel.
Test conditions that must not send before the normal path
This matrix is the chosen policy of the hypothetical service, not platform guarantees or completed test results. The service permits one active cart reminder and one reminder step per customer, using a preselected allowed channel/recipient. A new cart becomes a candidate only after checking the previous reminder's end and the separately defined sending cap.
| Exception/input | Expected behavior in this example | Main owner | Evidence |
|---|---|---|---|
| Normal nonbuyer; valid consent/recipient | Request only one reminder that passes the final check | CRM/sending development | Authorization reason, cart ID, send record/message ID |
| Already purchased at entry | Exit/exclude without creating the first message | CRM/QA | First step, exclusion path and no-request record |
| Late purchase webhook; source query shows purchase | Exclude at final sending gate | Order integration/sending development | Query result/time and exclusion reason |
| Purchase event received twice | Apply one purchase transition; do not recreate reminder | Data integration | Delivery-deduplication IDs and processing record |
| Old cart event after purchase | Do not revert ended C1 to nonpurchase | Data integration | Event time/version and rejected reverse transition |
| Purchase before final query / racing after it | Exclude the former; distinguish handoff and record residual risk for the latter | Sending development/operations | Query/request/purchase times; cancellation attempt/result |
| Two Journeys request the same reminder concurrently | Allow one via shared application sending record | CRM/sending development | Rejected duplicate reservation and chosen campaign |
| Same customer across devices/profiles | Deduplicate by customer and use selected recipient; hold unclear mappings | Identity integration | Customer/profile/subscription mapping and selection record |
| A logs out and B logs in on shared device | Exclude device from subsequent A candidates; block A-data access from old links | App development/QA | User switch, subscription mapping and link authorization |
| Opt-out while waiting | Exclude if reflected in final decision; separately trace handed-off requests | CRM/app development | Consent/subscription change time, exclusions and residual sends |
| Cancellation/partial/full refund | Do not resume the previous cart reminder | CRM/order operations | Maintained exit and any new-campaign approval |
| State-query failure/missing purchase event | Hold pending verification; recover through source reconciliation; do not count as normal nonbuyer | Integration operations | Hold reason, reconciliation work and unverified count |
Run actual tests on owned or authorized test shops, accounts and devices. Intentionally delay purchase events in the queue or resend one test event and compare with the normal path. No request created, no platform transmission and no device display are different verification results.
Record actual data, observations and retests in the CRM campaign QA scenarios and results workbook. Use the OneSignal customer Journey design workbook when agreeing entry, exit and reentry policy first.
One question before the next send
Choose one live cart reminder and ask the following.
“If this customer purchased, which record stops this send, and at what time?”
If the answer stops at “a segment excludes buyers,” trace when that segment updates, which customer/cart it refers to and how it affects already-waiting messages. Correct missing configuration in the existing tools. For data delays or conflicting sending paths, development, CRM and QA should assess the same timeline.
Reducing incorrect post-purchase sends requires clear exit policy, verifiable state and evidence that sending did not occur, rather than more Journeys.
When Journey design, implementation and verification responsibilities need to be agreed together, IXC CRM marketing automation describes the support scope.



