Skip to content

fix(replay): use live click attributes in breadcrumbs#20262

Open
logaretm wants to merge 6 commits intodevelopfrom
awad/js-2135-replay-click-live-attributes
Open

fix(replay): use live click attributes in breadcrumbs#20262
logaretm wants to merge 6 commits intodevelopfrom
awad/js-2135-replay-click-live-attributes

Conversation

@logaretm
Copy link
Copy Markdown
Member

@logaretm logaretm commented Apr 13, 2026

Fixes replay element attributes grabbing a potentially stale version of the attributes, we basically now prefer the live element if available, otherwise we keep the old behavior.

closes #20238

@logaretm logaretm requested a review from a team as a code owner April 13, 2026 17:33
Copilot AI review requested due to automatic review settings April 13, 2026 17:33
@linear-code
Copy link
Copy Markdown

linear-code bot commented Apr 13, 2026

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Cloudflare

  • Split alarms into multiple traces and link them by JPeer264 in #19373
  • Propagate traceparent to RPC calls - via fetch by JPeer264 in #19991

Core

  • Automatically disable truncation when span streaming is enabled in LangGraph integration by andreiborza in #20231
  • Automatically disable truncation when span streaming is enabled in LangChain integration by andreiborza in #20230
  • Automatically disable truncation when span streaming is enabled in Google GenAI integration by andreiborza in #20229
  • Automatically disable truncation when span streaming is enabled in Anthropic AI integration by andreiborza in #20228
  • Automatically disable truncation when span streaming is enabled in Vercel AI integration by andreiborza in #20232
  • Automatically disable truncation when span streaming is enabled in OpenAI integration by andreiborza in #20227
  • Add enableTruncation option to Vercel AI integration by nicohrubec in #20195
  • Add enableTruncation option to Google GenAI integration by andreiborza in #20184
  • Add enableTruncation option to Anthropic AI integration by andreiborza in #20181
  • Add enableTruncation option to LangGraph integration by andreiborza in #20183
  • Add enableTruncation option to LangChain integration by andreiborza in #20182
  • Add enableTruncation option to OpenAI integration by andreiborza in #20167
  • Export a reusable function to add tracing headers by JPeer264 in #20076

Deps

  • Bump axios from 1.13.5 to 1.15.0 by dependabot in #20180
  • Bump hono from 4.12.7 to 4.12.12 by dependabot in #20118
  • Bump defu from 6.1.4 to 6.1.6 by dependabot in #20104

Other

  • (browser) Add View Hierarchy integration by timfish in #14981
  • (node) Include global scope for eventLoopBlockIntegration by timfish in #20108
  • (node-native) Add support for V8 v14 (Node v25+) by timfish in #20125

Bug Fixes 🐛

Deno

  • Handle reader.closed rejection from releaseLock() in streaming by andreiborza in #20187
  • Avoid inferring invalid span op from Deno tracer by Lms24 in #20128

Other

  • (ci) Prevent command injection in ci-metadata workflow by fix-it-felix-sentry in #19899
  • (core, node) Support loading Express options lazily by isaacs in #20211
  • (e2e) Add op check to waitForTransaction in React Router e2e tests by copilot-swe-agent in #20193
  • (node-integration-tests) Fix flaky kafkajs test race condition by copilot-swe-agent in #20189
  • (replay) Use live click attributes in breadcrumbs by logaretm in #20262

Internal Changes 🔧

Ci

  • Remove node-overhead GitHub Action by mydea in #20246
  • Bump dorny/paths-filter from v3.0.1 to v4.0.1 by mydea in #20251
  • Remove codecov steps from jobs that produce no coverage/JUnit data by mydea in #20244

Deps

  • Bump hono from 4.12.7 to 4.12.12 in /dev-packages/e2e-tests/test-applications/cloudflare-hono by dependabot in #20119
  • Bump axios from 1.13.5 to 1.15.0 in /dev-packages/e2e-tests/test-applications/nestjs-basic by dependabot in #20179

Other

  • (bugbot) Add rules to flag test-flake-provoking patterns by Lms24 in #20192
  • (deps-dev) Bump vite from 7.2.0 to 7.3.2 in /dev-packages/e2e-tests/test-applications/tanstackstart-react by dependabot in #20107
  • (react) Remove duplicated test mock by s1gr1d in #20200
  • (size-limit) Bump failing size limit scenario by Lms24 in #20186
  • Fix lint warnings by mydea in #20250
  • Fix flaky ANR test by increasing blocking duration by JPeer264 in #20239
  • Add automatic flaky test detector by nicohrubec in #18684

🤖 This preview updates automatically when you update the PR.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Replay click breadcrumbs so recorded node attributes prefer the current/live DOM element attributes (to avoid stale rrweb mirror metadata), while still using rrweb metadata for the rest of the breadcrumb node payload. Adds a regression unit test covering attribute mutation/staleness.

Changes:

  • Update DOM breadcrumb construction to source attributes from the live Element when available.
  • Keep rrweb snapshot metadata as the source for tagName/textContent (when present).
  • Add a unit test ensuring live attributes win over stale mirror metadata.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/replay-internal/src/coreHandlers/handleDom.ts Prefer live element attributes for breadcrumb node attributes; add helper to serialize Element.attributes.
packages/replay-internal/test/unit/coreHandlers/handleDom.test.ts Add regression test asserting live attributes override stale rrweb meta; restore mocks after each test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@logaretm logaretm requested review from chargome and mydea April 13, 2026 17:42
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

size-limit report 📦

Path Size % Change Change
@sentry/browser 25.73 kB - -
@sentry/browser - with treeshaking flags 24.22 kB - -
@sentry/browser (incl. Tracing) 42.72 kB - -
@sentry/browser (incl. Tracing, Profiling) 47.35 kB - -
@sentry/browser (incl. Tracing, Replay) 81.64 kB +0.14% +108 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 71.18 kB +0.12% +80 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 86.35 kB +0.13% +111 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 98.55 kB +0.11% +105 B 🔺
@sentry/browser (incl. Feedback) 42.52 kB - -
@sentry/browser (incl. sendFeedback) 30.39 kB - -
@sentry/browser (incl. FeedbackAsync) 35.39 kB - -
@sentry/browser (incl. Metrics) 27.04 kB - -
@sentry/browser (incl. Logs) 27.19 kB - -
@sentry/browser (incl. Metrics & Logs) 27.86 kB - -
@sentry/react 27.48 kB - -
@sentry/react (incl. Tracing) 45.05 kB - -
@sentry/vue 30.56 kB - -
@sentry/vue (incl. Tracing) 44.58 kB - -
@sentry/svelte 25.75 kB - -
CDN Bundle 28.41 kB - -
CDN Bundle (incl. Tracing) 43.77 kB - -
CDN Bundle (incl. Logs, Metrics) 29.79 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 44.84 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 68.69 kB +0.13% +87 B 🔺
CDN Bundle (incl. Tracing, Replay) 80.73 kB +0.11% +88 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.77 kB +0.12% +90 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 86.26 kB +0.11% +88 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 87.29 kB +0.11% +88 B 🔺
CDN Bundle - uncompressed 83 kB - -
CDN Bundle (incl. Tracing) - uncompressed 129.82 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 87.14 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 133.24 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 210.51 kB +0.19% +382 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 247.08 kB +0.16% +382 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 250.48 kB +0.16% +382 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 260 kB +0.15% +382 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 263.38 kB +0.15% +382 B 🔺
@sentry/nextjs (client) 47.48 kB - -
@sentry/sveltekit (client) 43.2 kB - -
@sentry/node-core 57.86 kB - -
@sentry/node 174.8 kB +0.01% +14 B 🔺
@sentry/node - without tracing 97.63 kB +0.01% +9 B 🔺
@sentry/aws-serverless 114.98 kB +0.01% +6 B 🔺

View base workflow run

Copy link
Copy Markdown
Member

@billyvg billyvg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me, my only question is should we be mutating the event rather than returning a new event?

Comment on lines +128 to +131
!data ||
typeof data !== 'object' ||
!('source' in data) ||
data.source !== IncrementalSource.Mutation ||
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be simplified?

Suggested change
!data ||
typeof data !== 'object' ||
!('source' in data) ||
data.source !== IncrementalSource.Mutation ||
data?.source !== IncrementalSource.Mutation ||

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data is unknown due to the ReplayEventWithTime being typed as such, I didn't want to cast it to be able to simplify it. WDYT? is it safe to cast it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh hmmm… would using a type predicate work to narrow the event type down to an incremental snapshot event? we might have some helpers already

Comment on lines +132 to +133
!('attributes' in data) ||
!Array.isArray(data.attributes)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this too?

Suggested change
!('attributes' in data) ||
!Array.isArray(data.attributes)
!Array.isArray(data?.attributes)

Copy link
Copy Markdown
Member Author

@logaretm logaretm Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a similar thing here, data is typed as Record<"source", unknown> so optional chaining will case a type error without casting.

Should we maybe lax the types upstream or could we keep them for now to keep the changes simple.

logaretm and others added 6 commits April 14, 2026 10:48
Co-Authored-By: GPT-5 <noreply@anthropic.com>
Co-Authored-By: GPT-5 <noreply@anthropic.com>
Co-Authored-By: GPT-5 <noreply@anthropic.com>
Co-Authored-By: GPT-5 <noreply@anthropic.com>
Co-Authored-By: GPT-5 <noreply@anthropic.com>
@logaretm logaretm force-pushed the awad/js-2135-replay-click-live-attributes branch from f435b1a to e5bbdb0 Compare April 14, 2026 14:48
@logaretm
Copy link
Copy Markdown
Member Author

@billyvg we are mutating the mirrored state using the event as an input, not the event itself. Do you have another approach in mind?

Copy link
Copy Markdown
Member

billyvg commented Apr 14, 2026

@logaretm oh sorry misunderstood — do you know why mirror becomes stale?

@logaretm
Copy link
Copy Markdown
Member Author

@billyvg AFAIK (take it with lots of salt), replay stores an initial snapshot and then a stream of mutation events. Eventually it won't be stale. But because breadcrumbs read those attributes from the snapshot they will be always outdated since it doesn't fold the streamed mutation events to the values it records.

So this approach does this folding on the emit event, I tried initially finding the real element and reading from it but we will then have to mask every single attribute again since they will be unmasked, which felt like more work than folding the mutations in a flat loop.

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.

Replay click breadcrumbs capture stale element attributes when DOM attributes are mutated after initial snapshot

3 participants