Tour
Product tours and onboarding progress tracking. Platform admins publish versioned tour definitions - ordered steps with semantic UI targets, prerequisites, branching rules, A/B variants, and reset policies - and clients record progress events while the server tracks per-user completion flags server-side, so progress follows the user across devices.
When to reach for it: onboarding checklists that resume correctly on any device, feature-discovery tours, "saw this panel" UI flags, tutorials that branch by experiment variant or prior choices, drop-off analytics on activation funnels.
When not to: gameplay progression with objectives and reward payouts belongs to Quest; one-off milestone badges belong to Achievements; gating features by environment or audience belongs to Remote Config - tour flags record what a user has seen, not what they may use.
Concepts
- Definitions vs progress - a tour definition (steps, branching, variants) is admin-owned and versioned; progress is computed per user from a bitfield of completion flags, scoped to one definition version.
- Steps carry completion flags - each step names a
completion_flag; completing the step sets that bit. The definition fixes each flag's bit offset per version, so only declared flags exist. - Prerequisites gate availability - a step becomes available only once
every flag in its
prerequisiteslist is set; completing out of order is rejected, not reordered. - The current step is computed - branching rules are evaluated first; if none match, the first available step in index order is current.
- Versions - replacing a definition's steps bumps its version and applies the reset policy to every participant.
- Variants - deterministic A/B bucketing (SHA-256 of experiment, user, and version): stable within a version, re-rolled on version change.
- Admin vs user - defining, updating, deleting, analytics, and acting on another user's progress require a platform admin token.
Define a tour
Creation takes a JSON file with the full definition and requires a platform admin token:
snug tour create --file new-user-setup.json
# {"tour_id": "CDqLNRRwSXuZRPuZqBpj", "name": "docs4_new_user_setup", "version": 1, ...}
snug tour list --query setup --status active
snug tour get --tour CDqLNRRwSXuZRPuZqBpj
snug tour update --tour CDqLNRRwSXuZRPuZqBpj --status paused
snug tour delete --tour CDqLNRRwSXuZRPuZqBpjThe tour_id is server-generated - keep it from the create response; the
name is a searchable label, not an address. The definition file format
has its own page: Defining tours. Listing speaks the
shared search query grammar and shows
only active tours to non-admins; admins can pass --include-versions to
also see draft, paused, and deprecated definitions.
Record progress events
Clients report what the user did; the server derives everything else:
snug tour event --tour CDqLNRRwSXuZRPuZqBpj --event-type started
snug tour event --tour CDqLNRRwSXuZRPuZqBpj --event-type step_completed --step step_welcomeEvent types are started, step_seen, step_completed, flag_set,
dismissed, and abandoned. Over HTTP the same call is a POST returning
202 with the recomputed progress; captured live:
curl -X POST -H "Authorization: Bearer $SNUG_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"event_type": "step_completed", "step_id": "step_welcome"}' \
http://localhost:4000/api/v1/tours/CDqLNRRwSXuZRPuZqBpj/events{
"status": 202,
"msg": "Accepted",
"data": {
"tour_id": "CDqLNRRwSXuZRPuZqBpj",
"definition_version": 1,
"current_step_id": "step_profile",
"completed_steps": ["step_welcome"],
"mandatory_complete": false
}
}Completing a step whose prerequisites are unmet fails with
400 prerequisites_not_met; an unknown step_id is 404 step_not_found
(both reproduced). Event metadata is free-form JSON but capped - a 9 KB
payload was rejected with 400 limit_exceeded.
Read progress
snug --output json tour status docs-wave --tour CDqLNRRwSXuZRPuZqBpj{
"state": "in_progress",
"current_step_id": "step_profile",
"available_steps": ["step_profile", "step_advanced"],
"completed_steps": ["step_welcome"],
"seen_flags": ["saw_welcome"],
"variant": "power",
"mandatory_complete": false, "...": "..."
}The CLI requires the user argument; pass your own subject. Over HTTP,
GET /tours/{tour_id}/status defaults to the caller, and asking for
someone else with ?user= is admin-only - a regular token gets
403 insufficient_permissions (reproduced). States are not_started,
in_progress, completed, reset, and blocked; the moment every
mandatory step's flag is set, state flips to completed even with
non-mandatory steps remaining (verified live).
UI completion flags
Flags can also be set or cleared directly, without a step event:
snug tour flag-set --tour CDqLNRRwSXuZRPuZqBpj --flag sent_invite
snug tour flag-set --tour CDqLNRRwSXuZRPuZqBpj --clear sent_inviteOnly flags declared in the definition exist - an undeclared name is
404 flag_not_found (reproduced) - and admins may pass --user to act
on another user.
Resets
snug tour reset --tour CDqLNRRwSXuZRPuZqBpj --scope user # yourself
snug tour reset --tour CDqLNRRwSXuZRPuZqBpj --scope version # admin only
snug tour reset --tour CDqLNRRwSXuZRPuZqBpj --scope tour # admin onlyuser scope resets the caller (admins may target --user someone else);
version and tour scopes sweep every participant and require a platform
admin token - a regular token gets 403 insufficient_permissions
(reproduced). Version-change resets happen automatically; see
reset policies for what each mode
actually preserves.
Funnel analytics
Analytics require a platform admin token; a regular token gets
403 insufficient_permissions (reproduced):
snug tour analytics --tour CDqLNRRwSXuZRPuZqBpj # all-time
snug tour analytics --tour CDqLNRRwSXuZRPuZqBpj --window 2026-08-28 # one dayThe response reports started/completed totals, per-step
seen/completed/drop_off, per-variant completion rates, and how often
each branching rule fired. Counters are pre-aggregated into an all-time
window ("all") plus daily YYYY-MM-DD windows, scoped per definition
version (--version selects an older one; the active version is default).
Limits and configuration
Definitions are bounded at 200 steps, 512 flags, 100 branch rules, and
8 KiB of event metadata by default - tunable via the TOUR_* variables in
the Tour CONFIG reference.
Reference
- Tour API - every endpoint, callable
- Defining tours - the definition file format
- Related: Quest for objective-based progression, Achievements for milestone badges, Remote Config for feature gating