7.2 KiB
Cart/Checkout Recovery Strategies — Design Notes
Status: open design discussion, not scoped or built. This is a record of the reasoning behind an eventual "Recovery Sequences" feature, kept so the discussion doesn't have to be re-derived from scratch later. Nothing in this document is implemented.
See docs/cart.md for what's actually built today (the four-state cart classification,
CartAbandoned/CheckoutAbandoned events, DetectAbandonedCarts).
Why Abandoned Cart and Abandoned Checkout need different strategies
Established in docs/cart.md: Abandoned Cart (no order ever started) is a weak purchase-intent
signal and often unreachable (no identity for a true guest). Abandoned Checkout (a draft order
exists, placed_at IS NULL) is a strong intent signal and usually reachable, since checkout
typically captures an email/address even for a guest.
That difference in intent and reachability drives genuinely different marketing strategy, not just a different admin filter:
Abandoned Cart strategy — re-engagement, not completion
- On-site retargeting first (exit-intent popups, "still thinking it over?" banners on return visits) — often the only viable channel, since email may not exist yet.
- Ad platform retargeting (Meta/Google dynamic remarketing) is the dominant channel here specifically because it works off a browser/device signal, not an email address — the one thing reliably available for an anonymous cart.
- Soft messaging ("did you forget something?") rather than urgency-driven — intent is weak, so aggressive discounting is often poor ROI: it trains browsers who were never close to buying to expect a coupon.
- Longer, gentler cadence — a single reminder around 24h, maybe a second a few days out, sometimes trigger-based (a price drop, back-in-stock) rather than a fixed schedule.
Abandoned Checkout strategy — completion, not re-engagement
- Speed matters most. This is where the classic 1h/24h/72h recovery-email cadence lives — conversion drops sharply with delay, since the shopper is often still in a "was about to buy" mental state within the first hour.
- Direct, urgency-framed messaging ("complete your order"), sometimes showing cart contents/total, occasionally a countdown or limited-time incentive on later touches.
- Discount escalation pays off here — a small incentive (free shipping, 10% off) on the 2nd/3rd touch is standard, because it's nudging someone who already decided to buy past whatever blocked them (price shock, a broken payment step, indecision on shipping cost) — not manufacturing demand from nothing.
- SMS is more viable — checkout often captures a phone number, and the higher intent justifies a more direct channel than for cart-stage.
The broader strategy space (beyond cadence + discount)
Raised as context for how far a "Recovery Sequence" feature might eventually need to flex, without committing to building any of it yet:
Message-content strategies
- Social proof ("X people have this in their cart," reviews shown in the reminder)
- Scarcity/urgency framing (low-stock count, countdown timer on an offer)
- Personalized alternatives — a cheaper or complementary item instead of just re-showing the abandoned one, useful when the likely blocker was price
Channel strategies
- Email (the baseline; nothing built yet — see
docs/cart.md's "Recovery Sequences" section) - SMS — checkout-stage specifically, opt-in required
- Push notifications — not relevant yet given this project's storefront maturity, noted for completeness
- On-site remarketing (banner/modal on the shopper's next visit) — doesn't require email at all, arguably the highest-value channel for Abandoned Cart specifically
- Ad platform sync (pushing abandoned-cart product data to a custom audience for paid retargeting)
Escalation/segmentation strategies
- Value-based branching — a high-value abandoned checkout might skip straight to a bigger incentive rather than waiting through a full ladder
- Repeat-abandoner suppression — a customer who's abandoned 3+ times without ever completing either stops receiving emails (fatigue/spam risk) or gets a different tactic (e.g. a "what stopped you?" survey) instead of another discount
- New vs. returning customer branching — a first-time visitor's abandoned cart might warrant "welcome discount" framing instead of a generic recovery email, since the blocker was likely trust/unfamiliarity rather than price
Timing refinement
- Time-of-day/timezone-aware sending (don't fire a touch at 3am local time even if the delay technically elapsed)
- Cart-content-triggered timing — a fast-moving/low-stock item might warrant an earlier, more urgent first touch than a cart of always-in-stock staples
First-pass feature shape (discussed, not finalized)
An admin defines, independently per abandonment type (Abandoned Cart, Abandoned Checkout), an ordered sequence of touches. Each touch is three ideas:
- How long to wait since the abandonment began
- What offer to attach, optional — reusing whatever
Discountalready exists in the system rather than inventing a new pricing concept - A label, so staff can see what a touch represents in the admin UI
The system continuously re-evaluates every abandoned cart/checkout against its sequence, and when a cart becomes due for the next touch it hasn't had yet, that becomes a signal — this feature's responsibility ends there. Actually sending anything (email, SMS, on-site banner) is explicitly out of scope for this feature; something else, not yet designed, would consume that signal.
What this requires that isn't built yet
- A fixed "abandonment began at" timestamp, captured once and never re-derived — a
sequence needs to schedule touches from a stable starting point, not from
Cart::updated_at, which keeps moving every time the cart (or its own bookkeeping) is written to. This is the same underlying issue as the known bug indocs/cart.md's "Abandonment detection" section — fixing that bug properly (freezing the abandonment moment) is very likely a prerequisite for this feature, not a separate concern. - Re-evaluation, not one-shot detection —
DetectAbandonedCartstoday marks a cart abandoned once and stops; a sequence needs a cart to be revisited on every scheduler run to check "which touch, if any, is now due," for as long as it stays unrecovered.
Still undecided
- Which concern this belongs under. Not
Cart(it's not a cart-mechanics concern) — candidates raised: a newRecoveryconcern, orMarketing. Not decided. - How far the touch model needs to flex. The three-idea shape above (delay, discount, label) covers cadence + discount escalation cleanly, but doesn't yet accommodate channel choice, value-based branching, or segment targeting from the broader strategy list above. Whether those get folded into the touch model, layered on top some other way, or deliberately left out of v1 is unresolved.
- Whether "recovery" is cart/checkout-specific at all, or a more general "scheduled customer touch based on a triggering condition" mechanism that cart/checkout abandonment happens to be the first use case for.