All docs/Analytics

docs/architecture/posthog-event-tracking.md

PostHog Event Tracking — Hello & Library Apps

Goal

Measure where users progress and where they drop out — from first website submission through activation (first video received). Custom events fill the gaps that auto-captured $pageview events can't cover: actions within a page, AI interactions, and cross-app conversion.

What We Want to Answer

QuestionHow We Answer It
Where do users drop out of onboarding?$pageview funnel across step URLs
Which objectives do users choose?onboarding_objective_selected
Do users engage with AI features?onboarding_ai_action with type breakdown
How many users hit the auth wall?onboarding_auth_shown vs onboarding_published
Do published flows get shared?library_flow_url_copied + library_try_yourself_clicked
How quickly do flows get their first response?onboarding_publishedlibrary_first_video_received

Design Principles

  1. URL-based funnels first — PostHog auto-captures $pageview on every route. Each step has its own URL. No custom events for navigation.
  2. Custom events only where URLs aren't enough — In-page actions (generating questions, uploading a logo, picking an objective) are invisible to pageview tracking.
  3. Properties over events — One onboarding_ai_action with a type property instead of five separate events. Fewer events = simpler taxonomy.
  4. Never break the app — All tracking calls are wrapped in try/catch. Analytics failures are swallowed silently.

Events Mapped to User Journey

Onboarding Flow (Hello App)

 ┌─────────────────────────────────────────────────────────────────────────────────┐
 │                          ONBOARDING FLOW                                       │
 │                                                                                │
 │  /start                                                                        │
 │  ┌────────────────────────┐                                                    │
 │  │  Website URL form      │                                                    │
 │  │                        │──── onboarding_started ──────────────────┐          │
 │  │  [Resume dialog]       │──── onboarding_draft_resumed            │          │
 │  └────────────────────────┘                                         │          │
 │           │                                                         │          │
 │           ▼  $pageview                                              │          │
 │  /d/{id}/objective                                                  │          │
 │  ┌────────────────────────┐                                         │          │
 │  │  Pick testimonial goal │                                         │          │
 │  │                        │──── onboarding_objective_selected       │          │
 │  │  (predefined or custom)│     { objective_id, is_custom }         │  Events  │
 │  └────────────────────────┘                                         │  fire    │
 │           │                                                         │  at key  │
 │           ▼  $pageview                                              │  decision│
 │  /d/{id}/plan-interview                                             │  points  │
 │  ┌────────────────────────┐                                         │  within  │
 │  │  Confirm company info  │                                         │  each    │
 │  │  USPs, target audience │──── onboarding_company_confirmed        │  page    │
 │  │                        │     { has_usps, usp_count }             │          │
 │  └────────────────────────┘                                         │          │
 │           │                                                         │          │
 │           ▼  $pageview                                              │          │
 │  /d/{id}/configure  ─── OR ──  /d/{id}/studio                      │          │
 │  ┌────────────────────────────────────────────────┐                 │          │
 │  │  Configure & customize the flow                │                 │          │
 │  │                                                │                 │          │
 │  │  AI actions:                                   │                 │          │
 │  │    Generate questions ─── onboarding_ai_action │                 │          │
 │  │    Regenerate questions    { type: "..." }     │                 │          │
 │  │    Generate more                               │                 │          │
 │  │    Generate image                              │                 │          │
 │  │    Translate                                   │                 │          │
 │  │                                                │                 │          │
 │  │  Content:                                      │                 │          │
 │  │    Add language ───── onboarding_language_added │                 │          │
 │  │    Upload asset ───── onboarding_asset_uploaded │                 │          │
 │  │                       { asset_type, source }   │                 │          │
 │  │                                                │                 │          │
 │  │  Navigation:                                   │                 │          │
 │  │    → Studio ──── onboarding_exit_path          │                 │          │
 │  │    → Publish ─── { path: "studio"|"publish" }  │                 │          │
 │  └────────────────────────────────────────────────┘                 │          │
 │           │                                                         │          │
 │           ▼                                                         │          │
 │  ┌────────────────────────┐                                         │          │
 │  │  "Test & Share" click  │──── onboarding_publish_initiated        │          │
 │  │                        │     { is_authenticated }                │          │
 │  └────────────────────────┘                                         │          │
 │           │                                                         │          │
 │     ┌─────┴──────┐                                                  │          │
 │     ▼            ▼                                                  │          │
 │  Authed      Not authed                                             │          │
 │  (publish)   ┌────────────────┐                                     │          │
 │     │        │  /d/{id}/publish│                                    │          │
 │     │        │  Auth gate     │──── onboarding_auth_shown           │          │
 │     │        └───────┬────────┘                                     │          │
 │     │                │ (signs in)                                   │          │
 │     └────────┬───────┘                                              │          │
 │              ▼                                                      │          │
 │  ┌────────────────────────┐                                         │          │
 │  │  Publish to org        │──┬─ onboarding_published ───────────────┘          │
 │  │                        │  │  { flow_id, organization_id }                   │
 │  │                        │  └─ onboarding_publish_failed (on error)           │
 │  └────────────────────────┘                                                    │
 │              │                                                                 │
 └──────────────┼─────────────────────────────────────────────────────────────────┘
                │
                ▼  redirect to Library

Post-Publish Activation (Library App)

 ┌─────────────────────────────────────────────────────────────────────────────┐
 │                          LIBRARY APP                                       │
 │                                                                            │
 │  /dashboard/{flowId}   ($pageview auto-captured)                           │
 │  ┌──────────────────────────────────────────────┐                          │
 │  │  Flow management page                        │                          │
 │  │                                              │                          │
 │  │  Share actions:                              │                          │
 │  │    Copy URL ──── library_flow_url_copied     │                          │
 │  │    Try it    ──── library_try_yourself_clicked│                          │
 │  │                                              │                          │
 │  │  Activation:                                 │                          │
 │  │    0→1+ videos ── library_first_video_received                          │
 │  │    (auto-detected via polling)               │                          │
 │  │                                              │                          │
 │  └──────────────────────────────────────────────┘                          │
 │           │                                                                │
 │           ▼  click on respondent                                           │
 │  /dashboard/{flowId}/{respondentId}                                        │
 │  ┌──────────────────────────────────────────────┐                          │
 │  │  Respondent detail page                      │                          │
 │  │                                              │                          │
 │  │  On page load ── library_video_viewed        │                          │
 │  │                  { flow_id, respondent_id }   │                          │
 │  │                                              │                          │
 │  │  Export CSV ───── library_csv_exported        │                          │
 │  │                                              │                          │
 │  └──────────────────────────────────────────────┘                          │
 │                                                                            │
 └────────────────────────────────────────────────────────────────────────────┘

Event Reference

Onboarding Events

#EventWhere It FiresWhy It Exists
1onboarding_startedStartStepForm — after draft createdMarks true funnel entry (user committed a URL, not just loaded the page)
2onboarding_draft_resumedStartStepForm — resume dialogMeasures return-user rate and which step they left off at
3onboarding_objective_selectedObjectiveStepForm — on selectUnderstand distribution of use cases (testimonials, case studies, etc.)
4onboarding_company_confirmedCompanyStepForm — Continue clickGate between passive (auto-extracted) and active (user confirmed) data
5onboarding_ai_actionConfigureStepForm, StudioStepFormMeasure AI feature adoption — are users generating, regenerating, translating?
6onboarding_language_addedConfigureStepForm, StudioStepFormTrack multi-language adoption and total language count
7onboarding_asset_uploadedStudioStepFormUnderstand which asset sources users prefer (upload vs AI vs Unsplash)
8onboarding_exit_pathConfigureStepFormMeasure configure → studio vs configure → direct publish split
9onboarding_publish_initiatedStudioStepForm — "Test & Share"Captures intent to publish (before auth gate may interrupt)
10onboarding_auth_shownAuthGateForm — on mountMeasure how many users hit the auth wall, compare to publish success
11onboarding_publishedusePublishFlow — on successCore conversion event — draft became a live flow
12onboarding_publish_failedusePublishFlow — on errorTrack publish failures for debugging and reliability monitoring

Library Events

#EventWhere It FiresWhy It Exists
13library_flow_url_copiedFlowManageUI — copy buttonFirst signal of distribution intent
14library_try_yourself_clickedFlowManageUI — "Try it yourself" linkUser previewing their own flow (engagement signal)
15library_video_viewedRespondentViewWithDelete — on mountTrack which respondent videos users actually watch
16library_csv_exporteduseVideoDashboardExport — export clickData export as power-user engagement signal
17library_first_video_receivedFlowManageUI — 0→1+ video transitionKey activation metric — flow received its first real response

Funnels

Primary Onboarding Funnel

Built from auto-captured $pageview events plus the final custom conversion event:

Each arrow is a drop-off point. The funnel answers: At which step do most users abandon?

Auth Conversion Funnel

Specific to unauthenticated users:

Answers: What percentage of unauthenticated users complete signup and publish?

Post-Publish Activation Funnel

Measures what happens after a flow goes live:

Answers: Do users share their flow? Does it actually receive responses?


What We Intentionally Don't Track

Would-be EventReason
onboarding_step_viewedAuto-captured via $pageview on each step URL
onboarding_abandonedDerived from $pageleave + funnel drop-off analysis
library_page_viewedAuto-captured via $pageview
library_login / library_signupHandled by Clerk identity resolution in shared PostHog provider
Per-field edits (company name, question text)Too granular, not actionable — adds noise
Video playback controls (play/pause/seek)Belongs to Project B (end-user analytics), not Project A

Technical Implementation

Type-Safe Event Module

All events are defined in packages/core/src/web/posthog-events.ts:

// Typed event map — compile-time safety
export type HCEventMap = {
  onboarding_started: HCEvents.OnboardingStarted;
  onboarding_published: HCEvents.OnboardingPublished;
  library_flow_url_copied: HCEvents.LibraryFlowUrlCopied;
  // ...
};

// Generic capture function — wrong properties = compile error
export function captureHCEvent<T extends HCEventName>(
  event: T,
  properties: HCEventMap[T]
): void;

// Convenience wrappers for each event
export function trackOnboardingStarted(props: HCEvents.OnboardingStarted): void;
export function trackLibraryFlowUrlCopied(props: HCEvents.LibraryFlowUrlCopied): void;

Where Events Are Called

apps/hello/
├── components/steps/
│   ├── StartStepForm.tsx          →  onboarding_started, onboarding_draft_resumed
│   ├── ObjectiveStepForm.tsx      →  onboarding_objective_selected
│   ├── CompanyStepForm.tsx        →  onboarding_company_confirmed
│   ├── ConfigureStepForm.tsx      →  onboarding_ai_action, onboarding_language_added,
│   │                                 onboarding_exit_path
│   ├── StudioStepForm.tsx         →  onboarding_ai_action, onboarding_asset_uploaded,
│   │                                 onboarding_language_added, onboarding_publish_initiated
│   └── AuthGateForm.tsx           →  onboarding_auth_shown
├── hooks/
│   └── usePublishFlow.ts          →  onboarding_published, onboarding_publish_failed

packages/app-library/src/free/
│   └── FlowManageUI.tsx           →  library_flow_url_copied, library_try_yourself_clicked,
│                                     library_first_video_received

apps/library/
├── components/
│   └── RespondentViewWithDelete.tsx → library_video_viewed
├── hooks/
│   └── useVideoDashboardExport.ts  → library_csv_exported

Relationship to PostHog Projects

These events go to Project A (HappyClient Users) — tracking our users, not their end-users. Project B (Video Flow End-Users) is a separate concern handled by @repo/app-video-flow.

See posthog-analytics.md for the two-project architecture.


Related Documents