- Install @posthog/react and wrap app with PostHogProvider - Use VITE_PUBLIC_POSTHOG_KEY and VITE_PUBLIC_POSTHOG_HOST env vars - Use defaults: '2026-01-30' for recommended settings - Remove manual initAnalytics() call — Provider handles initialization - Analytics module now checks posthog.__loaded for readiness Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
98 lines
3.1 KiB
TypeScript
98 lines
3.1 KiB
TypeScript
/**
|
|
* PostHog product analytics wrapper.
|
|
*
|
|
* Tracks key user actions to understand product usage, activation,
|
|
* and engagement. All events are lightweight discrete actions.
|
|
*
|
|
* Free tier: 1M events/month (more than enough for current scale).
|
|
*
|
|
* PostHog is initialized via PostHogProvider in main.tsx.
|
|
* This module provides typed event helpers that import posthog-js directly
|
|
* (valid per PostHog docs for non-component code).
|
|
*/
|
|
import posthog from 'posthog-js'
|
|
|
|
/** Check if PostHog has been initialized (by the Provider). */
|
|
function isReady(): boolean {
|
|
try {
|
|
// posthog-js sets __loaded when init completes
|
|
return !!(posthog as unknown as { __loaded?: boolean }).__loaded
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
/** Identify a logged-in user. Call after login/fetchUser. */
|
|
export function identifyUser(user: {
|
|
id: string
|
|
email: string
|
|
role?: string
|
|
is_super_admin?: boolean
|
|
account_id?: string
|
|
}) {
|
|
if (!isReady()) return
|
|
posthog.identify(user.id, {
|
|
email: user.email,
|
|
role: user.role,
|
|
is_super_admin: user.is_super_admin,
|
|
})
|
|
if (user.account_id) {
|
|
posthog.group('account', user.account_id)
|
|
}
|
|
}
|
|
|
|
/** Reset identity on logout. */
|
|
export function resetAnalytics() {
|
|
if (!isReady()) return
|
|
posthog.reset()
|
|
}
|
|
|
|
// ─── Event Tracking ─────────────────────────────────────────────
|
|
|
|
/** Track a named event with optional properties. */
|
|
function track(event: string, properties?: Record<string, unknown>) {
|
|
if (!isReady()) return
|
|
posthog.capture(event, properties)
|
|
}
|
|
|
|
// Activation events
|
|
export const analytics = {
|
|
/** User created a new account */
|
|
accountCreated: () => track('account_created'),
|
|
|
|
/** User logged in successfully */
|
|
loginSuccess: () => track('login_success'),
|
|
|
|
/** User viewed a flow (opened the navigate page) */
|
|
flowViewed: (props: { flow_id: string; flow_type: string; flow_name: string }) =>
|
|
track('flow_viewed', props),
|
|
|
|
/** User started a session */
|
|
sessionStarted: (props: { session_id: string; flow_id: string; flow_type: string }) =>
|
|
track('session_started', props),
|
|
|
|
/** User completed a session */
|
|
sessionCompleted: (props: { session_id: string; flow_type: string; outcome: string }) =>
|
|
track('session_completed', props),
|
|
|
|
/** User generated an export (markdown, html, PDF, PSA) */
|
|
exportGenerated: (props: { session_id: string; format: string }) =>
|
|
track('export_generated', props),
|
|
|
|
/** User used an AI feature */
|
|
aiFeatureUsed: (props: { feature: 'copilot' | 'flow_assist' | 'session_to_flow' | 'kb_accelerator' | 'assistant_chat' }) =>
|
|
track('ai_feature_used', props),
|
|
|
|
/** User connected a PSA integration */
|
|
psaConnected: (props: { provider: string }) =>
|
|
track('psa_connected', props),
|
|
|
|
/** User created a shared session link */
|
|
sessionShared: (props: { session_id: string; visibility: string }) =>
|
|
track('session_shared', props),
|
|
|
|
/** User created a new flow */
|
|
flowCreated: (props: { flow_type: string; method: 'manual' | 'ai' | 'import' | 'session_to_flow' }) =>
|
|
track('flow_created', props),
|
|
}
|