Engagement states
What it is
Every customer with purchase history is in exactly one lifecycle state at any moment. The state says how "alive" the customer's buying relationship with your store is, and influences what kind of recommendations and content they get.
How it is computed
The state is recomputed every night, primarily from time since the last purchase:
| State | Rule |
|---|---|
| Hot | last purchase ≤ 30 days |
| Warm | 30-60 days |
| Cooling | 60-120 days |
| Lapsed | 120-180 days |
| Dormant | over 180 days |
| Recently won back | a lapsed/dormant customer who clicked an email within the last 7 days |
Two special rules:
- Rescue: a lapsed or dormant customer who clicks an email rises to "recently won back" — they have shown a sign of life.
- Consolidation: if a won-back customer buys within 30 days, they become "hot". If no purchase comes and the click ages out, they fall back to lapsed/dormant.
A customer with no purchases yet has no state — for them, see cold start.
How to interpret it
The most important rule: event vs state. The Insights "won back" number counts events in a period (how many customers entered the state during the period). The Audience filter shows a snapshot (who is in the state right now). "Recently won back" is deliberately a short-lived transitional state — the customer either buys (→ hot) or falls back. That is why the period event count is almost always larger than the current snapshot, and that is correct.
Common misreadings
- "The KPI says 72 won back, the filter shows 7 — where did 65 go?" — nowhere: they moved on through the lifecycle (some bought and are hot, some fell back). Event vs state.
- "A customer opened an email — why are they still dormant?" — the rescue is triggered only by a click, not an open (opens are noise due to Apple's privacy protection).
- "Why is a customer with purchases 'dormant'?" — the state looks at the recency of the last purchase, not the purchase count. Five orders two years ago = dormant.
Technical background
Classifier: lib/engine/learning/engagement-state.ts (thresholds
30/60/120/180 days; rescue click ≤ 7 days; consolidation purchase ≤ 30
days). Nightly cron update-engagement-state; transitions are logged to
customer_engagement_history (event counts come from there); the current
state lives on customers.engagement_state.
Last updated: 2026-07-06