diff --git a/src/components/PostHogSetup.tsx b/src/components/PostHogSetup.tsx index cc9032f9..4f3a9b9c 100644 --- a/src/components/PostHogSetup.tsx +++ b/src/components/PostHogSetup.tsx @@ -1,6 +1,7 @@ 'use client' import { useEffect } from 'react' +import { POSTHOG_REPLAY_PRIVACY_CONFIG } from '../lib/posthog-privacy' function PostHogInitializer({ site }: { site: string }) { useEffect(() => { @@ -18,12 +19,7 @@ function PostHogInitializer({ site }: { site: string }) { defaults: '2025-11-30', capture_exceptions: true, debug: import.meta.env.MODE === 'development', - session_recording: { - maskAllInputs: false, - maskInputOptions: { - password: true, - }, - }, + ...POSTHOG_REPLAY_PRIVACY_CONFIG, }) posthog.register({ site }) } diff --git a/src/lib/posthog-privacy.test.ts b/src/lib/posthog-privacy.test.ts new file mode 100644 index 00000000..3f9bd365 --- /dev/null +++ b/src/lib/posthog-privacy.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest' +import { POSTHOG_REPLAY_PRIVACY_CONFIG } from './posthog-privacy' + +describe('PostHog replay privacy', () => { + it('keeps session replay disabled for every shared browser surface', () => { + expect(POSTHOG_REPLAY_PRIVACY_CONFIG.disable_session_recording).toBe(true) + }) + + it('fails closed if session replay is enabled accidentally', () => { + expect(POSTHOG_REPLAY_PRIVACY_CONFIG).toMatchObject({ + capture_performance: { network_timing: false }, + enable_recording_console_log: false, + session_recording: { + maskAllInputs: true, + maskTextSelector: '*', + blockSelector: '[data-ph-sensitive]', + recordHeaders: false, + recordBody: false, + captureCanvas: { recordCanvas: false }, + collectFonts: false, + }, + }) + }) +}) diff --git a/src/lib/posthog-privacy.ts b/src/lib/posthog-privacy.ts new file mode 100644 index 00000000..ef9720db --- /dev/null +++ b/src/lib/posthog-privacy.ts @@ -0,0 +1,21 @@ +import type { PostHogConfig } from 'posthog-js' + +/** + * Session replay stays disabled on every surface that shares PostHogSetup, + * including docs, developers, and docs routes proxied through tempo.xyz. + * The remaining options fail closed if replay is ever enabled accidentally. + */ +export const POSTHOG_REPLAY_PRIVACY_CONFIG = { + disable_session_recording: true, + capture_performance: { network_timing: false }, + enable_recording_console_log: false, + session_recording: { + maskAllInputs: true, + maskTextSelector: '*', + blockSelector: '[data-ph-sensitive]', + recordHeaders: false, + recordBody: false, + captureCanvas: { recordCanvas: false }, + collectFonts: false, + }, +} satisfies Partial