An onboarding funnel is the ordered list of screens a new install passes through, counted by how many devices reached each one. To measure it you need an entry event, one event per step and a completion event. This guide builds one with ActivationPal, which has those three events built in.
What an onboarding funnel measures
A funnel has three parts:
- Entry: the install.
- Steps: each onboarding screen, in order.
- Completion: the moment you decide onboarding is over.
Every stage counts unique devices from the same install cohort, meaning devices whose first open falls inside the selected date range. No stage can exceed 100% of installs.
In ActivationPal the funnel is fixed: installed, your onboarding steps, completed, then paywall shown, plan selected and purchased.
Onboarding funnel events
Event names and prop keys are fixed, and the funnel matches on them exactly.
| Funnel stage | Event | SDK call | Sent when |
|---|
| Installed (entry) | first_open | automatic | Once per install, at first configure |
| Each step | onboarding_step | onboardingStep(index, id: "...", answer: "...") | A screen appears; index starts at 0 |
| Completed | onboarding_completed | onboardingCompleted() | Your chosen end of onboarding |
| Paywall shown | paywall_shown | paywallShown("onboarding") | The paywall appears; the argument is the placement |
| Plan selected | paywall_plan_selected | paywallPlanSelected("yearly") | A plan is tapped |
| Purchased | paywall_purchased | paywallPurchased("yearly") | The purchase succeeds |
Steps are ordered by index and labelled with id. answer is optional and splits a question step by the choice made. See the full event list.
Define entry and completion
Entry. Do not create your own start event. first_open is sent by the SDK once per install and is the 100% line. Never call it yourself.
Completion. Call onboardingCompleted() once, at the point where a user can use the app. Pick one place and keep it. If the paywall sits inside onboarding, decide whether completion comes before or after it and keep that fixed, because the paywall has its own stages after completed.
Steps. Send one call per screen, when the screen appears. Use one id per index, in snake_case and stable (goal, notifications). Send answer only on question screens, with low-cardinality values (lose_weight, not free text).
How to track onboarding steps
- Add the SDK and configure it at launch. The quickstart covers Native Swift; there are guides for Native Android, Flutter and React Native / Expo.
- Call
onboardingStep on each screen.
- Call
onboardingCompleted at the end, then the paywall helpers.
For a four-screen fitness app, that looks like this:
ActivationPal.configure(app: "myapp", key: "ap_pk_YOUR_KEY")
ActivationPal.onboardingStep(0, id: "goal", answer: "lose_weight")
ActivationPal.onboardingStep(1, id: "experience", answer: "beginner")
ActivationPal.onboardingStep(2, id: "notifications")
ActivationPal.onboardingStep(3, id: "account")
ActivationPal.onboardingCompleted()
ActivationPal.paywallShown("onboarding")
ActivationPal.paywallPlanSelected("yearly")
ActivationPal.paywallPurchased("yearly")
Events are buffered and flushed about every 10 seconds, at 20 buffered events and when the app goes to the background.
A sample onboarding funnel
These numbers are an example, not a benchmark:
- Installed: 1,000 (100%)
- goal: 900 (90%)
- experience: 780 (78%)
- notifications: 610 (61%)
- completed: 560 (56%)
Percentages are shares of installs. The step-to-step view is what finds the leak: experience to notifications keeps 610 of 780 (78%) and loses 170 devices, the largest loss in this funnel, so the notifications screen is the one to change first.
In the dashboard, hovering a stage shows its conversion from the stage before and how many users were lost there. Under goal and experience, the answers are listed with their counts.
To model a funnel before any event is sent, put step counts into the funnel calculator.
Onboarding funnel validation checklist
- Run a DEBUG build and look for
[ActivationPal] flushed N event(s) in the Xcode console.
- Open the dashboard live feed. Events appear seconds after a flush, and
env separates debug, testflight and release.
- Walk the whole onboarding once. You should see one
onboarding_step per screen, indexes 0, 1, 2 with no gaps or repeats, then one onboarding_completed.
- Delete and reinstall to send
first_open again. It fires once per install.
- Check that each row label matches its screen: one
id per index.
- Select a single app. With all apps selected, per-app steps collapse into one stage for reaching any onboarding step.
- A skippable or branching screen can show fewer devices than the screen after it, because each step counts the devices that reached that step. Treat that as a sign of a skip path, not a tracking bug.
- After a release that reorders screens, an index means a different screen than before. Compare date ranges that start after that release.
The same funnel numbers in ActivationPal are available to AI agents over MCP and a REST API, described in the agent API docs.