Replenishment
What it is
Replenishment is the prediction of when a customer is ready to re-buy a recurring product (food, litter, supplements). It is the engine's most direct "right product at the right moment" mechanism and drives Smaily automations.
How it is computed
- For every customer × product pair bought repeatedly, the engine computes a personal purchase interval (the median gap between purchases). A curve counts as reliable from 3 observations; before that, sector-typical intervals are used.
- "Product" here means the product family — different sizes/variants of the same product count as one buying cadence (a 30ml and then a 50ml of the same serum = a repeat purchase, not two separate products). The offer itself stays at the variant level: the engine offers the variant the customer bought last. Family detection requires the store to send the product's parent id (Shopify does; other platforms are following) — without it every variant counts as its own product, as before.
- From the 4th repeat purchase on, the interval adapts to the customer's personal consumption rate (a big household empties a bag faster).
- Next-purchase prediction = last purchase + personal interval. The recommendation window opens at 85% of the interval — slightly before running out rather than after.
- Two purchases less than a day apart (a split order or a correction) do not count as a purchase interval — otherwise the personal interval could collapse toward zero and replenishment would look due immediately. A customer whose repeat purchases are mostly same-day may need one more genuine (>1 day apart) repeat before a curve appears.
How to interpret it
rec_days_to_replenishis the days until predicted run-out for the customer's most timely recurring product (rec_replenish_sku). A small number = the right moment for an email.- The prediction is statistical, not a promise — the customer may buy in-store, gift the bag, or switch brands. The curve learns with every new purchase.
- Customers without repeat purchases get no replenishment fields — that is normal.
Common misreadings
- "The customer just bought — why are they offered the same product?" —
check the
rec_days_to_replenishvalue: if it is large, this is NOT a replenishment offer but e.g. a complementary product. If an automation sends the same product right after a purchase, the condition is probably set on the field's existence rather than its value (see the recipe below). - "The prediction looks wrong" — with fewer than 3 repeat purchases you are looking at the sector default, not a personal rhythm.
Smaily automation recipe
Typical trigger: send a replenishment email when
rec_days_to_replenish <= 5 and rec_replenish_sku is not empty. In
the email body use {{rec_replenish_sku}} and the recommendation slots as
usual.
Technical background
Curves: cadence_curves_customer (median interval, ≥3 observations =
"mature", consumption_rate_factor EWMA from the 4th repeat purchase — spec
§6.7.1). Purchases are grouped by product family (catalog.tags.product_id,
lib/catalog/product-family.ts); the curve is stored under the SKU of the
most recently bought variant. Window opening:
lib/engine/triggers/cadence-window-reached.ts (buffer_factor 0.85; the
cooldown is family-aware — a recent recommendation of a sibling variant
postpones the trigger). Smaily fields: rec_predicted_next_replenish_at,
rec_days_to_replenish, rec_replenish_sku (spec §8.5).
Last updated: 2026-07-14