129 lines
7.2 KiB
Markdown
129 lines
7.2 KiB
Markdown
# 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:
|
||
|
|
|
||
|
|
1. **How long to wait** since the abandonment began
|
||
|
|
2. **What offer to attach**, optional — reusing whatever `Discount` already exists in the
|
||
|
|
system rather than inventing a new pricing concept
|
||
|
|
3. **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 in `docs/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** — `DetectAbandonedCarts` today 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 new `Recovery` concern, or `Marketing`. 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.
|