Developers

Analytics

What are we tracking?

We use PostHog for analytics in both the web and desktop applications. The web application also uses Outlit for pageview tracking. You can opt-out from the settings menu in the desktop app.

User Journey Events

1. Visiting the Website

Events tracked on the web app (apps/web):

EventDescriptionPropertiesSource
hero_section_viewedUser views the landing page hero sectiontimestamproutes/_view/index.tsx
download_clickedUser clicks a download buttonplatform, spec, source, timestampcomponents/download-button.tsx, routes/_view/download/index.tsx
reminder_requestedUser requests a mobile reminderplatform, timestamp, emailroutes/_view/index.tsx
os_waitlist_joinedUser joins waitlist for unsupported OSplatform, timestamp, emailroutes/_view/index.tsx

The web app also has PostHog autocapture and pageview tracking enabled.

2. Getting Started

Events tracked when users first launch the desktop app:

EventDescriptionPropertiesSource
show_main_windowMain window is shown (fires on every app launch)-plugins/windows/src/ext.rs
onboarding_step_viewedUser views an onboarding stepstep, platformcomponents/main/body/onboarding/index.tsx
onboarding_completedUser finishes the onboarding flow-components/onboarding/final.tsx
user_signed_inUser signs in (triggers $identify to link anonymous ID)-auth/context.tsx
trial_startedUser starts a free trialplancomponents/onboarding/login.tsx, components/settings/general/account.tsx
ai_provider_configuredUser configures an AI providerprovidercomponents/settings/ai/shared/index.tsx
data_importedUser imports data from another appsourcecomponents/settings/data/index.tsx

3. Before Meetings

Events tracked when preparing for meetings:

EventDescriptionPropertiesSource
note_createdUser creates a new notehas_event_id (whether linked to calendar)store/tinybase/store/sessions.ts, components/main/shared.ts
file_uploadedUser uploads a filefile_type (audio or transcript), token_count (transcript only)components/main/body/sessions/floating/options-menu.tsx

4. During Meetings

Events tracked during active sessions:

EventDescriptionPropertiesSource
session_startedListening session startshas_calendar_event, stt_provider, stt_modelhooks/useStartListening.ts
tab_openedUser opens a tabview (tab type)store/zustand/tabs/basic.ts
search_performedUser performs a search-contexts/search/ui.tsx

5. After Meetings

Events tracked when working with completed sessions:

EventDescriptionPropertiesSource
note_editedUser edits a notehas_contentcomponents/main/body/sessions/note-input/raw.tsx
note_enhancedAI enhancement is triggeredis_auto, template_id (manual), llm_provider (auto), llm_model (auto)hooks/autoEnhance/runner.ts, components/main/body/sessions/note-input/header.tsx
message_sentUser sends a chat message-components/chat/input/hooks.ts
session_exportedUser exports a sessionformat (pdf or vtt), word_count (vtt), view_type (pdf), has_transcript (pdf), has_enhanced (pdf), has_memo (pdf)components/main/body/sessions/outer-header/overflow/export-transcript.tsx, export-pdf.tsx
session_deletedUser deletes a session/noteincludes_recordingcomponents/main/body/sessions/outer-header/overflow/delete.tsx
recording_deletedUser deletes a recording-components/main/body/sessions/outer-header/overflow/delete.tsx

6. Settings & Account Management

Events tracked when managing settings and account:

EventDescriptionPropertiesSource
settings_changedUser changes settingsautostart, notification_detect, save_recordings, telemetry_consentcomponents/settings/general/index.tsx
upgrade_clickedUser clicks upgrade buttonplancomponents/settings/general/account.tsx
user_signed_outUser signs out-components/settings/general/account.tsx

7. Notification Interactions

Events tracked when users interact with system notifications (plugins/notification/src/handler.rs):

EventDescriptionProperties
collapsed_confirmUser clicks collapsed notification to open app-
expanded_acceptUser accepts expanded notification-
dismissUser dismisses notification-
collapsed_timeoutCollapsed notification times out-

8. Server-Side Proxy Events

Events tracked by the API proxy layer. These use the $ prefix following PostHog conventions for built-in event types.

EventDescriptionPropertiesSource
$stt_requestSpeech-to-text request processed$stt_provider, $stt_duration, user_idcrates/transcribe-proxy/src/analytics.rs
$ai_generationLLM generation request processed$ai_provider, $ai_model, $ai_input_tokens, $ai_output_tokens, $ai_latency, $ai_trace_id, $ai_http_status, $ai_base_url, $ai_total_cost_usd, user_idcrates/llm-proxy/src/analytics.rs

User Properties

Properties set to track user context and configuration:

PropertyDescriptionTypeSource
is_signed_upWhether user has signed upsetauth/context.tsx, components/settings/general/account.tsx
platformOperating system (macos, linux, windows)setauth/context.tsx
os_versionOperating system versionsetauth/context.tsx
app_versionApplication versionsetauth/context.tsx
account_created_dateWhen account was createdset_onceauth/context.tsx
telemetry_opt_outWhether user opted out of telemetrysetcomponents/settings/general/index.tsx
has_configured_aiWhether user has configured an AI providersetcomponents/settings/ai/shared/index.tsx
planCurrent subscription plansetcomponents/onboarding/login.tsx, components/settings/general/account.tsx
trial_end_dateWhen trial endssetcomponents/onboarding/login.tsx, components/settings/general/account.tsx
spoken_languagesConfigured spoken languages for transcriptionsetstore/tinybase/persister/settings/persister.ts
current_stt_providerCurrently selected speech-to-text providersetstore/tinybase/persister/settings/persister.ts
current_stt_modelCurrently selected speech-to-text modelsetstore/tinybase/persister/settings/persister.ts
current_llm_providerCurrently selected LLM providersetstore/tinybase/persister/settings/persister.ts
current_llm_modelCurrently selected LLM modelsetstore/tinybase/persister/settings/persister.ts

Analytics Commands

Available methods for tracking events and properties:

  • event(payload) - Track a custom event with optional properties
  • setProperties(payload) - Set user properties (supports set and set_once types)
  • identify(userId, payload) - Link anonymous device ID to authenticated user ID using PostHog's $identify event
  • setDisabled(disabled) - Enable or disable analytics tracking
  • isDisabled() - Check if analytics is currently disabled

User Identification

When a user signs in, the identify command is called to link their anonymous device ID (machine fingerprint) to their authenticated user ID. This uses PostHog's $identify event with the $anon_distinct_id property, enabling:

  • Attribution of pre-login activity to the authenticated user
  • Unified user profiles across anonymous and authenticated sessions
  • Accurate conversion funnel analysis from first visit to active usage

The identification flow works as follows: before sign-in, events are tracked using the device fingerprint as the distinct ID. Upon successful authentication, identify(userId, payload) is called, which sends a $identify event to PostHog with both the new user ID and the anonymous device ID, merging the two identities.

Conversion Funnel Tracking

To track the user journey from website visit to active usage, use PostHog's funnel analysis with these key events:

  1. download_clicked (web) - User downloads the app
  2. show_main_window (desktop) - User launches the app
  3. onboarding_completed (desktop) - User finishes onboarding
  4. user_signed_in (desktop) - User signs in (triggers identity merge)
  5. note_created (desktop) - User creates their first note
  6. session_started (desktop) - User starts a listening session
  7. note_enhanced (desktop) - User uses AI enhancement

PostHog's $identify event links anonymous device IDs to authenticated user IDs, enabling accurate conversion analysis across the entire user journey.

Feature Flags

Char uses PostHog feature flags to control feature rollouts. The system is built on two layers:

  • crates/flag - A standalone Rust client for the PostHog feature flags API (/flags?v=2). It fetches flags by distinct_id and supports groups, person properties, and group properties.
  • plugins/flag - A Tauri plugin that wraps the flag client with caching and provides the FlagPluginExt trait for checking flags from application code via app.flag().is_enabled(feature).

Each feature defines a FlagStrategy:

StrategyBehavior
DebugEnabled only in debug builds
Posthog(key)Resolved via PostHog API (cached after first fetch)
Hardcoded(bool)Always enabled or disabled

Features can also be overridden at build time using environment variables (e.g., CHAT=1 forces the Chat feature on).

How to make changes?

See .cursor/commands/add-analytics.md for detailed instructions.