Skip to main content

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
Prerequisites: A running KaireonAI instance, an admin API key, and 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, so daysSinceSignup 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’s personalization 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 the Onboarding category and activates only during its day-window slot. Offers are active; eligibility is attached in step 4.
The Day-28 offer is a loss-leader — its up-front cost outweighs immediate margin, justified by the retained LTV the platform won’t see for months. Track that cost in the offer’s budget block; keep margin at its default (0 or higher — the API rejects negative margins).

4. Attach the staged eligibility rules

Every offer requires customer.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.
Encoding the stop condition as a rule on every offer is the pattern: activation flips one column; the 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. A time_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.
Together: at most one onboarding contact per customer per day, only Mon–Fri 09:00–18:00. A Saturday signup gets its day-1 welcome the following Monday morning.

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 uses method: "priority_weighted" (it honors the priority field directly rather than an ML propensity). The Compute node attaches completionPct.
A day-7 customer who hasn’t created a project gets exactly one decision back:
Five of the six offers failed qualification (wrong day-window); only the day-7 offer survived. With 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:
  1. Your product writes activatedAt into the customer record — through the same data path that populates the ds_customer table (a pipeline, a bulk upsert, or your app’s own write). On the next /recommend, the Enrich stage loads a non-null customer.activatedAt, every onboarding offer’s not_exists rule fails, and the flow returns count: 0 — the program has stopped for this customer.
  2. Optionally, record the activation as an outcome for measurement. Register an outcome type once, then record it against the recommendation the customer acted on. (/respond records interactions and updates models; it does not itself mutate schema columns.)
Encoding the stop as a decisioning gate — rather than as branching logic inside the flow — keeps the flow simple: activation flips one column, the rules see it, and the offers stop firing.

8. What success looks like

Track three numbers on the Operations dashboard: If activation rate drops below target, the most common cause is the schema not capturing the right signal. Add a column, update the pipeline that maintains it, re-deploy — the flow picks up the new signal at the next decision.

9. What’s next

  • Activation-funnel A/B. Add a flowConfig.experiment holdout 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.plan rule to fork the flow per tier.
  • Inactivity side-flows. If customer.lastLoginDaysAgo climbs while still in onboarding, route to a re-engagement sub-flow via a conditional node — 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.