"Our onboarding converts at 61%" is a sentence that means almost nothing. Completion isn't the goal; paying users are. The question worth asking is which steps cause people to reach the value moment that later shows up as a trial — and you can only ask it if behavior and purchases live on the same user record.
First, make the question answerable
Purchases live in RevenueCat; taps live in your analytics tool. If each SDK invented its own anonymous ID, the onboarding-to-paid question has no table to run on. The fix is the one-ID pattern: generate a single identifier on first launch and hand the same value to both SDKs. We wrote up the full pattern and its failure modes in why your PostHog and RevenueCat numbers never match — everything below assumes that join exists.
The five events that carry the whole analysis
onboarding_step— one event per screen, with a step index property. Resist inventing twelve event names for twelve screens.onboarding_completed— fired once, at the moment you consider onboarding done.paywall_shown— every time, not just the first.- Trial start — from RevenueCat, so it's the store's truth rather than your button handler's optimism.
- Purchase / renewal — also from RevenueCat, joined by the shared ID.
Five events is deliberately few. Every extra event is a maintenance cost and another chance for definitions to drift between app versions.
The two cuts that matter
1. Completed vs skipped
Split trial starts by whether the user finished onboarding. This is the highest-signal number in the whole area, and it's routinely a multiple — completers trialing at several times the rate of skippers. If your gap is small, your onboarding isn't delivering the value moment; if it's huge, everything that increases completion is plausibly worth money.
2. Step drop-off × eventual conversion
Per-step retention alone misleads: a step can pass 95% of users while adding nothing. For each step, look at what fraction of the users who saw it eventually paid. Steps where that curve kinks downward are friction; steps where survivors convert far better are where the value lands. Cutting a harmless-looking screen that sits before the kink is often the cheapest conversion win available.
Indie-scale honesty
- Weekly cohorts, not daily. At tens of installs a day, daily rates are coin flips.
- ~50 users per bucket before you act; below that, one family sharing a promo code moves your percentages.
- Compare app versions, not calendar weeks, when you ship a change — "before vs after the release" is the comparison that maps to a decision.
- Don't slice thrice. Completed-vs-skipped by version is already four buckets; adding country and device makes noise look like insight.
What to actually change
- Move the value moment earlier. Whatever your app's "oh, it works" instant is, onboarding exists to reach it — permissions and preference screens can usually wait until after.
- Show the paywall after value, then test the exception. Per-viewer conversion is usually better after the aha; total volume is bigger up front. The joined data tells you which effect wins for you.
- Cut steps that don't move eventual conversion. If step 4's survivors pay at the same rate as step 3's, step 4 is decoration.
- Re-measure per release. Onboarding changes are cheap to ship and cheap to revert when the release-over-release numbers say so.
FAQ
How long should onboarding be?
As long as it takes to reach the value moment and no longer. Length isn't the variable that matters; the kink in the step-vs-eventual-conversion curve is.
Can I run this analysis with PostHog + RevenueCat connectors?
Yes, if your ID mapping between the two systems is airtight. The analysis is identical; the join is the hard part, and connectors sync events, not identities.
Is 61% onboarding completion good?
Meaningless in isolation. A 40% completion with completers trialing at 5× skippers beats a 90% completion that changes nothing downstream.