Skip to content

Session replays render again: attribute masking made surgical - #37

Merged
shivamsn97 merged 5 commits into
mainfrom
fix/replay-attribute-masking
Sep 10, 2026
Merged

Session replays render again: attribute masking made surgical#37
shivamsn97 merged 5 commits into
mainfrom
fix/replay-attribute-masking

Conversation

@shivamsn97

Copy link
Copy Markdown
Member

Session replays recorded since the redesign reconstruct as mostly blank pages: mask_all_element_attributes: true masks class and style along with everything else, and the redesign's styling is entirely class-driven — so the replayed DOM matches almost no CSS rule, and sections that reveal via a class change never appear.

The flag is now off, replaced with a surgical maskAttributeFn that strips query strings from recorded href values (unsubscribe links carry signed tokens — the original reason for the blanket mask). Input masking and [data-private] text masking are unchanged, so the privacy posture is identical: no typed input and no token ever reaches a recording.

Verification: config change only — deployed and confirmed live via posthog.config on the production page; the behavioural proof is the next recorded session rendering fully in PostHog.

mask_all_element_attributes masked class and style too, which starved session replays of every CSS hook and rendered whole pages blank — the design is entirely class-driven. Attribute hygiene is now surgical: maskAttributeFn strips query strings from recorded hrefs (unsubscribe links carry signed tokens); inputs stay masked as before. No change to what visitors' browsers send or receive — this only affects how replays reconstruct.
The boot and scroll reveals existed only as completed forwards-fill CSS animations, which leave no DOM trace — a replayer's paused animation clock froze them at their opacity-0 base, reconstructing whole pages as blank. The boot script now stamps html.booted once load-time animations finish, useSeen stamps data-settled on revealed sections, and the stylesheet pins every final frame as plain style behind those markers. Pixel-identical for live visitors; verified by killing all animations on a booted, scrolled page — nothing disappears.
The SDK's parse and init cost ~150ms of main thread that idle-deferral cannot keep out of a throttled audit's blocking window. Loading on the first pointerdown, keydown, touch or scroll makes a visitor who only reads cost nothing; anyone who acts is captured from that first act, replay included. Surveys module disabled — none are configured. Recording and masking behavior unchanged.
The hero now paints statically — the boot theater plays only on decorations, never on the largest contentful element — and the page rides the framework's new asset controls: inlined stylesheets, no module preloads, after-paint hydration, ISR envelopes on cacheable loaders. Fonts move to self-hosted /fonts (generated by scripts/sync-fonts.mjs), injected after first paint behind metric-true fallbacks; demo screenshots become webp with the first card eager. Accessibility lands at 100: contrast-true faint/terminal tokens, folio numerals as aria-hidden pseudo-content, landmark fixes. Two shipped cascade bugs fixed along the way: the request-log pane's dark bed was bleaching to white, and a rulebar border collision caused the site-wide layout shift.
Picks up the framework's new configuration reference, build-optimization and deployment sections.
@shivamsn97
shivamsn97 merged commit c9efbbb into main Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant