Tutorial: Onboarding & Activation
The first 30 days of a customer relationship are decisive. A new customer who hits their activation moment — the first action that proves the product works for them — converts to long-term retention. A new customer who doesn’t, churns silently. This tutorial builds a flow that nudges new customers through the activation funnel, escalates if they stall, and stops the program the moment activation fires — so the next message is the right one for an active customer, not another activation prompt. Business scenario: a SaaS product’s activation event is “first project created and shared with a teammate”. Roughly 40% of signups never get there. Marketing wants a 30-day sequence: day 1 welcome → day 3 tutorial nudge → day 7 use-case examples → day 14 success story → day 21 personal-help offer → day 28 cancellation-prevention. The moment a customer activates, the sequence terminates. What you’ll build:- A Customer schema with signup, activation, and progress signals
- 6 onboarding offers staged across the 30-day window
- A flow that selects the correct step by tenure-since-signup
- An activation gate that stops the program per customer
- Weekday-business-hours contact policies
curl + jq.
Time: 25–30 minutes.
0. Set up your shell
1. Define the schema
The flow gates on tenure-since-signup and recency-of-login. The formula engine can’t compute those date differences at decision time, sodaysSinceSignup and lastLoginDaysAgo are real columns your data pipeline refreshes daily. activatedAt stays null until the customer activates — that null is the signal the program should keep running.
activatedAt being null is what keeps the program alive; the offer rules below all require it to be absent.
2. Create the category with a progress score
A computed custom field surfaces a per-customer output value in the response’spersonalization object — useful for an in-app progress bar. It runs in the Compute stage (after gating), so it’s a display value, not a gate. The formula uses only supported syntax (arithmetic, comparison, ternary); outputType is number or text.
completionPct is a quick health score: 0 = “haven’t started”, 100 = “completed both activation precursors”.
3. Define the 6 staged offers
Each offer belongs to theOnboarding category and activates only during its day-window slot. Offers are active; eligibility is attached in step 4.
budget block; keep margin at its default (0 or higher — the API rejects negative margins).
4. Attach the staged eligibility rules
Every offer requirescustomer.activatedAt to be absent (the not_exists operator passes only when the field is null/unset) plus its day-window and step-specific conditions. Rules on the same offer are AND-combined.
not_exists gate sees it; every onboarding offer stops firing at once (covered in step 7).
5. Contact policies — weekdays, business hours, once a day
Onboarding messages over the weekend feel desperate. Atime_window policy restricts delivery to Mon–Fri business hours (day names are three-letter, capitalized; hours are 0–23), and a customer_total_cap limits to one onboarding contact per day.
6. Wire the onboarding flow
Onboarding is deterministic by design — the right offer for day-7 is always the day-7 offer, so the Score node usesmethod: "priority_weighted" (it honors the priority field directly rather than an ML propensity). The Compute node attaches completionPct.
method: "priority_weighted", score mirrors the offer’s priority.
7. The activation stop
Activation is a fact about the customer record, so the stop is driven by data, not by a special API call. Two things happen when a customer activates:-
Your product writes
activatedAtinto the customer record — through the same data path that populates theds_customertable (a pipeline, a bulk upsert, or your app’s own write). On the next/recommend, the Enrich stage loads a non-nullcustomer.activatedAt, every onboarding offer’snot_existsrule fails, and the flow returnscount: 0— the program has stopped for this customer. -
Optionally, record the activation as an outcome for measurement. Register an outcome type once, then record it against the recommendation the customer acted on. (
/respondrecords interactions and updates models; it does not itself mutate schema columns.)
8. What success looks like
Track three numbers on the Operations dashboard:| Metric | Source | Target |
|---|---|---|
| Activation rate (30d) | customers with non-null activatedAt ÷ signups | > 60% |
| Avg days to activate | mean of activatedAt − signupDate | < 14 days |
| Onboarding cost per activated customer | onboarding impressions × cost-per-message ÷ activations | < $0.50 |
9. What’s next
- Activation-funnel A/B. Add a
flowConfig.experimentholdout that gets no onboarding messages. If activation rate is similar, the program is decorating outcomes that would have happened anyway. - Plan-specific tracks. Enterprise customers need longer, more white-glove onboarding than free-tier. Add a
customer.planrule to fork the flow per tier. - Inactivity side-flows. If
customer.lastLoginDaysAgoclimbs while still in onboarding, route to a re-engagement sub-flow via aconditionalnode — see Journeys. - In-product nudges. Some onboarding steps are in-app banners, not emails. Request them with
channel: "in_app"to surface the right step contextually during a session.
See Churn Prevention, Cross-Sell, and Winback for the other three core lifecycle flows. Together they cover the four phases of the customer relationship: onboard, grow, retain, recover.