PLG OS

Implementation worksheet · 6 min read

A React Native Onboarding Offline Recovery Plan

Treat onboarding progress as local-first state that syncs, not as a server call per step. Write each completed step locally the moment it completes, queue the sync, and reconcile when connectivity returns. Then specify five interruption cases explicitly: no connectivity at start, connectivity lost mid-flow, the app backgrounded mid-step, the process killed by the OS, and the app updated mid-onboarding. For each, say what the user sees on return. The default behaviours — a spinner that never resolves, or silently restarting from step one — are both worse than an honest 'you completed 3 of 5, continue?'.

Onboarding is written on a desk with good wifi and a simulator that never backgrounds. Real first sessions happen on a train, on a phone that takes a call halfway through, on a device the OS is happy to kill for memory. Every one of those produces a state the flow was never designed to resume from, and the failure is invisible in development because none of them happen there.

Put it into practice

1. Persist step completion locally, immediately

The moment a step completes, write it to local storage before anything network-bound. A step that is only recorded server-side is a step lost to a dropped request. Sync is a background concern; the user's sense of progress must not depend on it.

2. Queue the sync and make it idempotent

Each completion carries a stable identifier so replaying it is harmless. The queue drains when connectivity returns, and a completion sent twice produces the same result. Without idempotency the natural retry behaviour double-counts progress, which then shows up as impossible completion rates in reporting.

3. Decide what onboarding can do offline, and say so

Most explanatory steps work offline. Steps requiring a server — verify an email, connect an integration, load real data — do not. Mark each step as offline-capable or not, and when an offline user reaches a blocked step, say plainly that it needs a connection and let them continue past it rather than trapping them.

4. Handle backgrounding as a first-class case

On resume, decide per step: continue where they were, restart the current step, or re-evaluate from the beginning. Most steps should resume; steps whose underlying screen may have changed should re-evaluate. What must never happen is resuming into a coach mark pointing at a view that is no longer mounted.

5. Survive process death

The OS kills backgrounded apps routinely. On cold start, read persisted progress before rendering anything onboarding-related, and resume rather than restart. Restarting a five-step flow from step one because the OS reclaimed memory is the most common version of this failure and reads to the user as the app forgetting them.

6. Handle the mid-onboarding app update

The user completes three steps, the app updates, and step four has been renamed or removed. Persist step identifiers rather than indexes, and on version change reconcile: completed steps that still exist stay completed, steps that no longer exist are dropped, and new steps are inserted. Persisting an index means an update silently changes which step someone is on.

The five interruption cases

Copy this structure into your review document and record your observed result for each row.

The five interruption cases
CaseWhat the user sees on returnRequiresTested
No connectivity at startoffline-capable steps run; blocked steps markedstep offline flags
Connectivity lost mid-flowprogress kept, sync queued silentlylocal-first writes
App backgrounded mid-stepresume or re-evaluate, per stepper-step resume policy
Process killed by the OScold start resumes at the right steppersisted identifiers
App updated mid-onboardingcompleted steps preserved, new steps insertedidentifiers not indexes
Sync replayed after reconnectno double-countingidempotent completions
Two devices, same userno restart on the second deviceserver reconciliation

A failure worth checking

Persisting the step index instead of the step identifier. Someone is on step 4 of 6, the app updates, and a step is inserted at position two. On resume they are now on a different step than the one they were on, with earlier steps marked complete that they never saw. Nothing errors, the analytics look normal, and the user quietly experiences an onboarding that skipped the explanation they needed. Identifiers cost nothing extra and make the reconciliation possible at all.

Common questions

Should onboarding block until it syncs?

No. Blocking the user's first experience on a network round trip is the wrong trade, and on a poor connection it is the difference between completing onboarding and uninstalling. Write locally, show progress immediately, sync in the background, reconcile later.

How do I test these cases?

Deliberately: airplane mode mid-flow, force-quit between steps, and a simulator with background app refresh disabled. All three take minutes and none of them happen on their own during development, which is exactly why these bugs reach production.

Basis and scope

This is a proposed implementation method using illustrative examples, not a measured benchmark or a customer case study. Prepared with AI assistance. Validate product-specific behavior against current documentation and your own test environment.

Continue with PLG OS

Explore onboarding →