PostHog Masking Lab

Sandbox for validating PostHog session-replay masking before recommending PostHog to the security team. Each field below is labeled with its expected behavior so a recorded session can be inspected against ground truth.

How to verify:
  1. Fill every field with recognizable test data (do NOT use real PII — use fake values you can grep for).
  2. Masking is configured in the SDK, not a dashboard toggle. This site runs a strict posture set in src/components/posthog.astro: maskAllInputs: true + maskTextSelector: '*', so every input and all text is masked by default.
  3. Click Submit (fires a masking_lab_submitted event), then open the session in PostHog → Session replay.
  4. Confirm masked content renders as ••• / blank, ph-no-mask elements render their literal values, and ph-no-capture elements are replaced with a blank block.
Group A — Default (no directive)

Under the strict SDK config, every input and all text here is masked in replay.

Group B — Blanked (ph-no-capture)

Elements are replaced with a blank block in replay — stronger than masking. Nothing about the value reaches PostHog.

Group C — Revealed (ph-no-mask)

Force-unmasked: should render literal values in replay even though global masking is on.

Group D — Static text blocks

Verifies maskTextSelector: '*' masks non-input text, and ph-no-mask reveals it.

GROUP-D-DEFAULT — plain paragraph. Masked by the global text selector.

GROUP-D-MASKED — also masked; should appear as bullets in replay.

GROUP-D-NOMASK — should always be readable in replay.

Group E — Images

Validates image masking. ph-no-capture blanks the image; default images follow the recorder's image handling.

Default favicon
Default
Blanked favicon
ph-no-capture
Revealed favicon
ph-no-mask
Group F — Region wrapper

A whole subtree marked ph-no-capture — every descendant is blanked in replay.

GROUP-F-REGION — entire div is blanked.

GROUP-F-SPAN inside blanked region