abandoned-checkout
One journey that opens a recovery window when a checkout starts, and closes it quietly when the order lands.
Journeys
Section titled “Journeys”| Journey | What it does |
|---|---|
abandoned-checkout |
Reminds someone who left items in their cart, and stops if they buy. |
Events it needs
Section titled “Events it needs”These are names your own app sends through track, not names Cowliss defines. Rename them in the copied files to whatever your app already sends.
| Event | Named by |
|---|---|
checkout_started |
abandoned-checkout |
purchase_completed |
abandoned-checkout |
Copy it
Section titled “Copy it”cow init --blueprint abandoned-checkoutEvery file above lands in your repo, yours to edit. In a repo that already has a cow.json, add it with cow add blueprint abandoned-checkout instead.
The pattern
Section titled “The pattern”Recovery window with a success mark. checkout_started opens a 24-hour window; a purchase_completed inside it closes the window quietly and marks the cart cart_recovered, a trait your segments and other journeys can read (“recovered once” vs “never”). Silence spends exactly one reminder email and closes.
Reach for it when
Section titled “Reach for it when”Abandoned carts, incomplete onboarding checklists, unfinished KYC: any funnel step with a clear completion event and a deadline.
Make it yours
Section titled “Make it yours”Rename the events and the email to your domain. To escalate instead of sending once, loop with a second api.waitForEvent and a stronger second email before closing.
The journey
Section titled “The journey”Abandoned-checkout recovery: checkout_started opens a 24-hour window. A
purchase_completed inside it closes the window quietly and marks the cart
recovered, a trait your segments and other journeys can read. Silence
spends exactly one reminder email and closes.
marketing and no enrollment, so one shopper goes through this once,
ever: their second abandoned cart is not nagged about. Add
enrollment: { cooldown: "30d" } to reach a repeat abandoner again, a
month after their last reminder.
Blueprint: add it with cow add blueprint abandoned-checkout; rename the
events and the email to your domain’s vocabulary.
import { defineJourney } from "@cowliss/cli/journeys";
/** * Abandoned-checkout recovery: `checkout_started` opens a 24-hour window. A * `purchase_completed` inside it closes the window quietly and marks the cart * recovered, a trait your segments and other journeys can read. Silence * spends exactly one reminder email and closes. * * `marketing` and no `enrollment`, so one shopper goes through this once, * ever: their second abandoned cart is not nagged about. Add * `enrollment: { cooldown: "30d" }` to reach a repeat abandoner again, a * month after their last reminder. * * Blueprint: add it with `cow add blueprint abandoned-checkout`; rename the * events and the email to your domain's vocabulary. */export default defineJourney({ trigger: { event: "checkout_started" }, purpose: "marketing", description: "Reminds someone who left items in their cart, and stops if they buy.", tags: ["demo", "checkout"], run: async (event, api) => { const purchased = await api.waitForEvent("purchase_completed", { timeout: "24h", }); if (purchased) { await api.traits.set("cart_recovered", true); return; } // The checkout link belongs to your store, so the trigger event carries // it; the email drops its button when the prop is missing. const checkoutUrl = event.properties.checkoutUrl; const me = await api.profile.get(); await api.send.email({ template: "abandoned-checkout", props: { checkoutUrl: typeof checkoutUrl === "string" ? checkoutUrl : undefined, firstName: typeof me.traits.firstName === "string" ? me.traits.firstName : undefined, }, }); },});Its scenario
Section titled “Its scenario”cow test replays this on a virtual clock: the trigger fires at the start, events arrive at their offsets, and expect is the ordered list of capability calls the run must make, each input matched as a subset.
{ "user": { "id": "usr_1", }, "events": [], "expect": [ { "activity": "sendEmail", "input": { "template": "abandoned-checkout", "props": { "firstName": "Ada" } } } ]}cow test abandoned-checkout --scenario scenarios/abandoned-checkout.timeout.json