A good mobile app onboarding flow asks one goal question, delivers first value before any account wall, requests each permission when the feature needs it, and shows the paywall after value. Make each screen one measured step so you can see which one loses people.
Design the app onboarding flow
Start with a goal question
One question about what the user wants gives you something to personalize and something to measure. Record the choice as the answer on that step. The ActivationPal dashboard splits the answers under the step, so you see which goals new users pick.
Show value before you ask for anything
Put the first useful moment ahead of the account wall, the permission prompts and the paywall. A user who has seen what the app does has a reason to say yes to the next request.
Time the permission prompts
Ask for a permission when the user is about to use the feature that needs it, with one line saying why. On iOS the system prompt is shown once, so a denial can only be reversed in Settings.
If you add a screen that explains notifications before the system prompt, give it its own step id, such as notifications. Then the opt-in screen has its own row in the funnel.
Place the paywall
Show the paywall after the user has seen value, and make it a step you can read. paywallShown("onboarding") separates this placement from a paywall opened in settings. Compare plan selected with purchased to see whether people choose a plan and then stop at the purchase sheet.
Onboarding carousel or interactive screens
A carousel works for three or four short screens with a visible skip button. Give each swipe page its own step id. A long carousel shows up in the funnel as a steady loss on every page, which is the sign to cut it or replace it with a screen where the user does something.
Map every onboarding screen to a step
Decide the screens first, then give every screen one call. With the ActivationPal Swift SDK that is onboardingStep: one call per screen, in order, index from 0, an id, and an answer on screens where the user makes a choice.
// One call per screen, in order. Index starts at 0.
ActivationPal.onboardingStep(0, id: "goal", answer: "lose_weight")
ActivationPal.onboardingStep(1, id: "notifications")
ActivationPal.onboardingCompleted()
// The paywall, if onboarding ends with one.
ActivationPal.paywallShown("onboarding")
ActivationPal.paywallPlanSelected("yearly")
ActivationPal.paywallPurchased("yearly")
ActivationPal.paywallDismissed()
Call onboardingStep when the screen appears, and onboardingCompleted on the last screen. The funnel row for a screen is keyed by its index, rows are ordered by index, and the row is labelled with the id. Keep each screen's index and id the same across releases, so a screen stays one row. Setup is in the quickstart and every call is listed in the events reference.