guided_tour is a Flutter package for guided tours where the tour is data, kept out of your screens.
A screen joins a tour by carrying a TourKey. That's the entire contract. Tour definitions live in
their own files and never import a widget.
What it's for
Onboarding that spans screens and waits on real app state. Not "point at four things on one screen", but "walk someone through placing an order across four screens, waiting on their basket and then on the payment API."
Decisions
- No dependencies, no registration, no global keys, no router lock-in. Routing goes through a three-method seam. The complete GoRouter adapter fits in the README.
- Every step declares how it ends: next, a tap, a route, a signal, a condition, or a branch.
- Interactive steps are real. The tap goes to the actual widget and runs its actual handler. Nothing is simulated.
-
Async-safe. Feature code reports milestones like
payment.ok. They do nothing when no tour is running, and they're buffered, so an early API response isn't lost. - The package owns no product decisions. Whether a user "has seen" a tour is product storage, not a package concern.
- No made-up progress. No "step 3 of 7" when a tour branches, because the total isn't known.
Under the hood
- The spotlight sits above every route, dialog and sheet, and ignores touches when idle.
- Targets are re-measured every frame, wait for route transitions to settle, and scroll into view.
- If a dialog covers the target, the step waits underneath instead of failing.
- Screen-reader announcements are built in.
- The example app has architecture tests proving tour files never import screens.
- 80 tests, 16 of them in the example app.