You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Components styled via shadowRoot.adoptedStyleSheets lose all styling mid-replay when an SPA navigation detaches and reattaches them. Reported by a customer whose header renders unstyled ("mobile mode") from the navigation onward while the live page looks correct.
On the live page the browser preserves a moved element's shadow root and adopted sheets, so the recorder (which already tracks that shadow root) correctly emits no new AdoptedStyleSheet event. The replayer however rebuilds the re-added host with a fresh, empty shadow root.
Changes
The replayer keeps a lastAdoptedStyleIds map (latest adopted styleIds per host id) and re-adopts when it attaches a shadow root for a known host: immediately during live playback, or via the existing pending-adoptions flush during fast-forward. The map is cleared wherever the style mirror resets (full snapshot rebuild, playback from baseline, destroy), so stale ids never cross a document swap.
Replay-side only, so playback of existing recordings is fixed retroactively.
Verification:
New regression test (live + fast-forward paths) with a fixture modeling the reported recording. It fails without the fix.
replayer, adopted-stylesheet-rejected, and fast-forward suites: 70/70 pass.
The reported recording replayed headlessly against both builds: unpatched drops to 0 adopted sheets on the header after the navigation, patched keeps 1 sheet / 30 rules through the end.
Release info Sub-libraries affected
Libraries affected
All of them
posthog-js (web)
posthog-js-lite (web lite)
posthog-node
posthog-react-native
@posthog/react-native-plugin
@posthog/react
@posthog/ai
@posthog/convex
@posthog/next
@posthog/nextjs-config
@posthog/nuxt
@posthog/openfeature-node-provider
@posthog/openfeature-web-provider
@posthog/rollup-plugin
@posthog/webpack-plugin
@posthog/types
@posthog/browser-common
Checklist
Tests for new code
Accounted for the impact of any changes across different platforms
Accounted for backwards compatibility of any changes (no breaking changes!)
Took care not to unnecessarily increase the bundle size
If releasing new changes
Ran pnpm changeset to generate a changeset file
If releasing new changes
🤖 Agent context
Autonomy: Human-driven (agent-assisted) — or — Fully autonomous
This diff touches code involved in past incidents. This is a heads-up, not a verdict: read the matched sections of INCIDENTS.md and answer their review questions before merging.
For a judgment on whether this diff has the same failure mode, run the replay-incident-risk skill locally: open a Claude session in the repo root and ask it to review your diff with that skill. Or run node .agents/skills/replay-incident-risk/check.mjs and answer the review questions for each matched class yourself.
Matched 1 past incident pattern(s) (diff vs origin/main):
## Replay reconstruction and player security [path match]
Recorded page content is untrusted input. Anything the replayer places in the top-level document sits outside the sandbox iframe: copying recorded attributes without an allowlist caused a stored XSS via canvas onerror (Jul 2026). Never copy on* handlers or src/srcset/href you did not construct.
Touched paths:
- packages/rrweb/rrweb/src/replay/index.ts
- packages/rrweb/rrweb/test/replayer.test.ts
Read: .agents/skills/replay-incident-risk/INCIDENTS.md#class-5-replay-reconstruction-and-player-security
This check is advisory. It flags resemblance to past incidents, not correctness.
For a judgment pass on whether this diff has the same failure mode, run the
`replay-incident-risk` skill in a Claude session from the repo root, or answer the
review questions in the matched sections of .agents/skills/replay-incident-risk/INCIDENTS.md yourself.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Components styled via
shadowRoot.adoptedStyleSheetslose all styling mid-replay when an SPA navigation detaches and reattaches them. Reported by a customer whose header renders unstyled ("mobile mode") from the navigation onward while the live page looks correct.On the live page the browser preserves a moved element's shadow root and adopted sheets, so the recorder (which already tracks that shadow root) correctly emits no new
AdoptedStyleSheetevent. The replayer however rebuilds the re-added host with a fresh, empty shadow root.Changes
The replayer keeps a
lastAdoptedStyleIdsmap (latest adopted styleIds per host id) and re-adopts when it attaches a shadow root for a known host: immediately during live playback, or via the existing pending-adoptions flush during fast-forward. The map is cleared wherever the style mirror resets (full snapshot rebuild, playback from baseline, destroy), so stale ids never cross a document swap.Replay-side only, so playback of existing recordings is fixed retroactively.
Verification:
replayer,adopted-stylesheet-rejected, andfast-forwardsuites: 70/70 pass.Release info Sub-libraries affected
Libraries affected
Checklist
If releasing new changes
pnpm changesetto generate a changeset fileIf releasing new changes
🤖 Agent context
Autonomy: Human-driven (agent-assisted) — or — Fully autonomous