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.
| Case | What the user sees on return | Requires | Tested |
|---|---|---|---|
| No connectivity at start | offline-capable steps run; blocked steps marked | step offline flags | |
| Connectivity lost mid-flow | progress kept, sync queued silently | local-first writes | |
| App backgrounded mid-step | resume or re-evaluate, per step | per-step resume policy | |
| Process killed by the OS | cold start resumes at the right step | persisted identifiers | |
| App updated mid-onboarding | completed steps preserved, new steps inserted | identifiers not indexes | |
| Sync replayed after reconnect | no double-counting | idempotent completions | |
| Two devices, same user | no restart on the second device | server 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.