Install → Onboarding Funnel & Cross-Surface Identity
This page is for the growth team. It explains the funnel events, which surface and identifier owns each one, how the website and desktop journeys merge into a single Amplitude user, and the limits of that merge.
The funnel
HabitatZero Download Started → HabitatZero Desktop App Installed → Onboarding Started → Onboarding Completed
| Event | Surface that emits it | Identifier before merge | When |
|---|---|---|---|
HabitatZero Download Started | Website (apps/frontend) | web device_id W (anonymous) | Visitor clicks a /download/mac or /download/win link. Carries platform (mac/windows). |
HabitatZero Desktop App Installed | Desktop (apps/desktop) | desktop device_id D (anonymous) | First app launch after install, once per installation. |
Onboarding Started | Desktop | firebaseUserId (identified) | After Google sign-in, first tracked session. |
Onboarding Completed | Desktop | firebaseUserId (identified) | Permission screen marks onboarding complete. |
App Open (every launch) and On App Background (window hidden) are also
emitted by desktop but are not funnel steps. Install via Referrer is a
separate cross-promo acquisition event (once per attributed install), named to
match the Fabulous/iOS data repos.
How the surfaces merge into one user
There are two anonymous Amplitude device_ids and one user_id that unifies
them. The merge key is always firebaseUserId — the Firebase Auth user id.
Both desktop (setUserId(firebaseUserId) at sign-in) and the backend Identify
call use this exact id. A Google sub, email, or internal database id would
silently fail to merge.
- Desktop → user (reliable). The anonymous desktop events on
device_id D(App Installed,App Open,On App Background) re-associate to the user when the desktop callssetUserId(firebaseUserId)at sign-in. No cross-surface work is needed; this always connects. - Website → user (best-effort). At the Google
/auth-startbridge — opened in the same browser as the website visit — the webdevice_id Wis forwarded to the backend, which calls Amplitude's server-side Identify with{ device_id: W, user_id: firebaseUserId }. This mergesDownload Started(and the website visit) into the same user.
Attribution limitation (read this before trusting website→install numbers)
The website → install link only works when Google sign-in starts in the same browser context as the download. It will undercount when:
- the user downloads in one browser and signs in from another,
- the browser is in incognito/private mode,
- storage was cleared between download and sign-in, or
- the Amplitude SDK's storage is blocked.
In all those cases the install → onboarding funnel (desktop only) still works fully — only the website → install join undercounts. Treat website attribution as a floor, not an exact count.
Mac vs Windows interpretation
App Installed fires at first app launch, the industry-standard proxy for
install (the DMG/installer has no analytics SDK).
- Windows: the NSIS installer auto-launches the app on finish, so first launch ≈ install completion — a tight proxy.
- macOS: no auto-launch — the user drags the
.appfrom the DMG and launches it manually (possibly later), soApp Installed≈ first manual launch. Some users drag but never launch; those are unmeasurable.
Amplitude auto-captures the OS, and desktop events report platform as macOS
or Windows (web surfaces stay Web), so segment the funnel by OS/platform to
compare the two side by side.
Expected one-time bump
There is intentionally no migration guard for users already installed when this
release ships. The installed base is small, so the first launch after upgrading
may emit App Installed once for existing users. Discount the release-week
spike when reading the funnel.
How to validate the merge
In Amplitude User Lookup on staging, with a single browser:
- Click a download link on the website (fires
Download Started). - Launch the desktop app and sign in with Google (same browser for the
/auth-startbridge). - Confirm one Firebase
user_idshowsHabitatZero Download Started,HabitatZero Desktop App Installed,Onboarding Started, andOnboarding Completedtogether.
If the website event does not join, check that sign-in happened in the same
browser as the download and that the SDK could read its stored device_id.