Analytics Events
FocusFlow analytics event names use result-style names such as Started, Completed, Viewed, Created, Copied, and Tapped. Add or update rows here in the same change that adds or renames an AnalyticsEvent constant.
Describe every property a row sends — what it means and its type — rather than only naming it. For a property with a fixed set of values (an enum), list all the values. Use None when an event sends no properties.
Desktop Events
Source: apps/desktop/src/renderer/core/telemetry/events.ts
| Event | Trigger | Properties |
|---|---|---|
Accessibility Permission Completed | Accessibility permission request resolves or fails during onboarding. | permissionStatus |
Account Restricted Shown | The account-restricted surface first becomes visible (operator kill-switch active). Fires once per transition to restricted — covers both the reactive 403 IPC broadcast and the proactive entitlements snapshot path. | None |
App Open | The desktop app finishes launching and analytics initializes — fires once per app launch, anonymous before sign-in. Mirrors the iOS App Open lifecycle event. | None |
Calendar Link Screen Viewed | The connect-Google-Calendar onboarding step is shown (once per mount) — the gate between the onboarding questions and the permission screen. Makes drop-off at the calendar step visible in the onboarding funnel. | None |
Calendar Sign In Completed | Google Calendar connection completes and the calendar link state is confirmed as linked. | None |
Desktop App CTA Clicked | User clicks the download button on a desktop-only CTA in the web build. | source (string) — which feature surfaced the CTA, one of recording, dictation, meetingDetection, or template.placement (string) — where the CTA rendered, one of meetingBanner or templateLanding. |
Desktop App CTA Viewed | A desktop-only feature surface renders the download-desktop CTA in the web build (once per mount). | source (string) — which feature surfaced the CTA, one of recording, dictation, meetingDetection, or template.placement (string) — where the CTA rendered, one of meetingBanner or templateLanding. |
Dictation Failed | A dictation attempt ends in an error of any kind (connect, provider, finalize, or paste failure). | cause (string) — failure classification, one of engine_dead, internal_error, websocket_close, websocket_error, auth, rate_limit, timeout, parse_error, or unknown (fallback for anything unclassified). |
Dictation Limit Reached | The rolling dictation-seconds cap is hit — fired once per cap event, covering both the mid-session dictation.terminate stop and the start/retry admission 429. | None |
Dictation Started | Dictation recording begins after the trigger shortcut is pressed and the microphone is authorized. | None |
Dictation Succeeded | A dictation attempt finishes with text pasted (auto-paste, manual paste, or recovered after retry). | durationSeconds (number) — whole seconds from recording start to paste, including processing time.pasteResult (string) — how the text landed, one of autoPasted (inserted into the focused field) or manualPaste (left on the clipboard for the user to paste). |
Document Created | A workspace document is created. | None |
HabitatZero Desktop App Installed | First time the desktop app opens after install (once per installation). Anonymous at fire time; stitches to the user via the desktop device_id at sign-in. Top of the install → onboarding funnel. | None |
HabitatZero First Note Created | A user's first desktop note is created with active cross-promo attribution still inside the activation window. | placement, ref, source, trialDays, optional UTM properties |
Install via Referrer | A cross-promo-attributed install, recorded once per installation the first time cross-promo attribution is available (after sign-in). Mirrors the iOS Install via Referrer acquisition event. | placement, ref, source, trialDays, optional UTM properties |
Meeting Duration Auto Ended | The desktop meeting soft cap stops an active recording after the warning was not postponed. | None |
Meeting Duration Postponed | A user taps Postpone on the meeting duration warning. | postponeCount |
Meeting Duration Warning Shown | The desktop meeting soft-cap warning is shown on the notification overlay. | postponeCount |
Meeting Max Length Reached | The server hard backstop ends an active meeting through meeting_max_duration or meeting.terminate. | None |
Meeting Note Created | A meeting note is created from the tray, deeplink, or note creation flow. | None |
Meeting Recording Ended | A recording session finalizes (manual stop or its note is deleted mid-recording). | durationSeconds (number) — whole seconds of wall-clock from recording start to finalize, including any paused time.hasTranscript (boolean) — whether any transcript content was captured during the session.transcriptWordCount (number) — words captured during the session (0 when none). |
Meeting Recording Started | Recording starts for a note. | source |
Meeting Summary Completed | A transcript summary websocket event completes for a note. | None |
Meeting Transcribed | A recording session first receives transcript content. | None |
Microphone Permission Completed | Microphone permission request resolves during onboarding. | permissionStatus |
On App Background | The desktop main window is minimized or hidden (closing the window hides it in this tray app). Fired from the main process on window minimize/hide — deliberately not on focus loss/occlusion while the window is still visible. Mirrors the iOS On App Background lifecycle event. | None |
Onboarding Completed | The permission screen marks onboarding complete. | None |
Onboarding Question Answered | A user answers one onboarding question. | questionId, optionId, optionLabel, step |
Onboarding Questions Completed | The onboarding questions flow completes. | Onboarding answer user-property payload |
Onboarding Questions Started | The onboarding questions flow first mounts. | source |
Onboarding Started | A signed-in user begins onboarding for the first tracked app session. | source |
Permission Screen Viewed | The permission screen is shown during onboarding. | None |
Purchase Success | A Stripe subscription first becomes active or trialing after checkout/webhook processing. | ownerId, workspaceId, planCode, priceLookupKey, currency, amount, interval, stripeSubscriptionId, source |
Quarter Goal Created | A quarterly planning goal is created. | None |
Sales Success | A Stripe invoice payment succeeds, including the first invoice and recurring invoices. | ownerId, workspaceId, planCode, currency, amount, interval, stripeSubscriptionId, stripeInvoiceId, currentPeriodEnd, source |
Share Link Copied | A share URL is copied from sharing UI. | entityType, source |
Share Link Tapped | The share toggle/action is tapped from the sharing popover. | entityType, source |
Subscription Manage Opened | A user opens the Stripe billing portal from Plans and Billing. | None |
Subscription Purchase Failed | A checkout start/create call fails before Stripe checkout can be completed. | planCode, currency, errorMessage |
Subscription Purchase Started | A user starts hosted or embedded checkout from Plans and Billing. | planCode, currency, source |
Subscription Purchase Succeeded | Client-side constant reserved for checkout success UI; authoritative server-side first activation is tracked to Amplitude as Purchase Success. | None |
System Audio Permission Completed | System audio permission request resolves, fails, or times out during onboarding. | permissionStatus |
Template Open In App Tapped | A visitor on the web templates landing (/templates/<slug>) taps "Already have the app? Open it" — the only action that fires the desktop deeplink now that boot no longer auto-fires it. | placement (string) — always templateLanding.source (string) — always template.templateSlug (string) — the resolved template slug. |
Template Personalize Tapped | The user taps the personalize/use button on a template detail page (primary pill or worksheet preview open). | templateName, templateSlug |
Template Sign In Viewed | The web build shows the Canva-style sign-in preview for a resolved template after a signed-out visitor lands on /templates/<slug>. | templateName, templateSlug |
Todo Created | A non-goal todo is created. | None |
Top Goal Created | A daily top goal is created or promoted. | goalPosition, source |
Web App Viewed | The web build finishes loading and analytics initializes — the web analogue of App Open; fires once per page load. | None |
Web Sign In Completed | The web OAuth redirect returns and the code exchange plus browser-session creation succeed. | None |
Web Sign In Started | A user clicks Continue with Google on the web sign-in screen, before the OAuth redirect. | None |
Weekly Goal Created | A weekly planning card is created. | source |
Weekly Goal Planned | An unplanned weekly card is scheduled into a day or next week. | placement |
Frontend Public Share Events
Source: apps/frontend/src/lib/analytics/events.ts
| Event | Trigger | Properties |
|---|---|---|
HabitatZero Download Page Visited | A visitor views the Habitat Zero download page. | Optional placement, ref, source, trialDays, and UTM properties |
HabitatZero Download Started | A visitor starts a platform download via the /download/mac or /download/win link. | platform (mac or windows), optional placement, ref, source, trialDays, and UTM properties |
Open With Habitat Zero Tapped | A visitor taps an "Open with Habitat Zero" call to action on a public share page. | placement |
Public Share Viewed | A public share page is viewed. | entityType |