Skip to content

feat(browser): Add View Hierarchy integration#14981

Merged
timfish merged 19 commits intodevelopfrom
timfish/feat/browser-view-hierarchy
Apr 13, 2026
Merged

feat(browser): Add View Hierarchy integration#14981
timfish merged 19 commits intodevelopfrom
timfish/feat/browser-view-hierarchy

Conversation

@timfish
Copy link
Copy Markdown
Collaborator

@timfish timfish commented Jan 11, 2025

image

By default it captures the entire DOM, but it is configurable:

Capture only React components (uses attributes added by Sentry bundler plugins):

import * as Sentry from '@sentry/browser';

Sentry.init({
  dsn: '__DSN__',
  integrations: [Sentry.viewHierarchyIntegration({
    onElement: ({componentName}) => componentName ? {} : 'children'
  })],
});

Capture only Web Components:

import * as Sentry from '@sentry/browser';

Sentry.init({
  dsn: '__DSN__',
  integrations: [Sentry.viewHierarchyIntegration({
    onElement: ({tagName}) => tagName.includes('-') ? {} : 'children'
  })],
});

@codecov
Copy link
Copy Markdown

codecov bot commented Jan 11, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
628 1 627 299
View the top 1 failed tests by shortest run time
client-app-routing-instrumentation.test.ts Creates a navigation transaction for app router routes
Stack Traces | 30s run time
client-app-routing-instrumentation.test.ts:19:5 Creates a navigation transaction for app router routes

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

@AbhiPrasad
Copy link
Copy Markdown
Contributor

woah

what does it look like with minified class names? (and you don't have react component annotations or similar?)

@timfish
Copy link
Copy Markdown
Collaborator Author

timfish commented Jan 14, 2025

By default it's capturing getComponentName(element) || element.tagName.toLowerCase(). So the above example actually has no React components on the page, it's simply displaying HTML elements and the tag names with a hyphen (-) are Web Components.

Here is the full event:
https://sentry-sdks.sentry.io/issues/6212345017/events/c6fa1362bdf5410487cf8461d6168583/

@mydea mydea mentioned this pull request Mar 28, 2025
2 tasks
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 11, 2026

Codecov Results 📊


Generated by Codecov Action

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 11, 2026

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 9,088 - 9,313 -2%
GET With Sentry 1,819 20% 1,747 +4%
GET With Sentry (error only) 6,034 66% 5,980 +1%
POST Baseline 1,186 - 1,180 +1%
POST With Sentry 595 50% 603 -1%
POST With Sentry (error only) 1,051 89% 1,054 -0%
MYSQL Baseline 3,287 - 3,272 +0%
MYSQL With Sentry 438 13% 445 -2%
MYSQL With Sentry (error only) 2,616 80% 2,698 -3%

View base workflow run

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 26, 2026

size-limit report 📦

Path Size % Change Change
@sentry/browser 25.73 kB +0.02% +5 B 🔺
@sentry/browser - with treeshaking flags 24.22 kB +0.03% +6 B 🔺
@sentry/browser (incl. Tracing) 42.72 kB -0.03% -11 B 🔽
@sentry/browser (incl. Tracing, Profiling) 47.35 kB -0.03% -10 B 🔽
@sentry/browser (incl. Tracing, Replay) 81.53 kB -0.02% -12 B 🔽
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 71.1 kB -0.02% -10 B 🔽
@sentry/browser (incl. Tracing, Replay with Canvas) 86.23 kB -0.02% -13 B 🔽
@sentry/browser (incl. Tracing, Replay, Feedback) 98.44 kB -0.02% -13 B 🔽
@sentry/browser (incl. Feedback) 42.52 kB +0.02% +8 B 🔺
@sentry/browser (incl. sendFeedback) 30.39 kB +0.03% +8 B 🔺
@sentry/browser (incl. FeedbackAsync) 35.39 kB +0.03% +9 B 🔺
@sentry/browser (incl. Metrics) 27.04 kB +0.02% +3 B 🔺
@sentry/browser (incl. Logs) 27.19 kB +0.02% +3 B 🔺
@sentry/browser (incl. Metrics & Logs) 27.86 kB +0.02% +3 B 🔺
@sentry/react 27.48 kB +0.02% +4 B 🔺
@sentry/react (incl. Tracing) 45.05 kB -0.02% -9 B 🔽
@sentry/vue 30.56 kB +0.01% +3 B 🔺
@sentry/vue (incl. Tracing) 44.58 kB -0.03% -12 B 🔽
@sentry/svelte 25.75 kB +0.01% +2 B 🔺
CDN Bundle 28.41 kB +0.02% +4 B 🔺
CDN Bundle (incl. Tracing) 43.76 kB -0.03% -9 B 🔽
CDN Bundle (incl. Logs, Metrics) 29.79 kB +0.02% +3 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) 44.83 kB -0.03% -9 B 🔽
CDN Bundle (incl. Replay, Logs, Metrics) 68.6 kB +0.01% +5 B 🔺
CDN Bundle (incl. Tracing, Replay) 80.63 kB -0.02% -9 B 🔽
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.66 kB -0.02% -10 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback) 86.16 kB -0.01% -8 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 87.19 kB -0.02% -10 B 🔽
CDN Bundle - uncompressed 83 kB +0.01% +4 B 🔺
CDN Bundle (incl. Tracing) - uncompressed 129.79 kB +0.01% +4 B 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 87.14 kB +0.01% +4 B 🔺
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 133.2 kB +0.01% +4 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 210.13 kB +0.01% +4 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 246.67 kB +0.01% +4 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 250.07 kB +0.01% +4 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 259.58 kB +0.01% +4 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 262.97 kB +0.01% +4 B 🔺
@sentry/nextjs (client) 47.47 kB -0.02% -7 B 🔽
@sentry/sveltekit (client) 43.2 kB -0.03% -10 B 🔽
@sentry/node-core 57.85 kB +0.01% +5 B 🔺
@sentry/node 175.07 kB +0.01% +8 B 🔺
@sentry/node - without tracing 97.97 kB +0.03% +21 B 🔺
@sentry/aws-serverless 115.22 kB +0.02% +17 B 🔺

View base workflow run

@github-actions
Copy link
Copy Markdown
Contributor

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you apply the label PR: no-auto-close I will leave it alone ... forever!

@github-actions
Copy link
Copy Markdown
Contributor

Closing due to inactivity after stale warning. Comment or reopen when ready to continue, and use PR: no-auto-close to opt out of automatic closure.

@github-actions github-actions bot closed this Mar 28, 2026
@timfish timfish reopened this Mar 28, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 28, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 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

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.

@timfish timfish removed the PR: stale label Mar 28, 2026
@Lms24
Copy link
Copy Markdown
Member

Lms24 commented Mar 30, 2026

@timfish anything that we still need to change here to get this out of draft?

@timfish
Copy link
Copy Markdown
Collaborator Author

timfish commented Mar 30, 2026

I need to add an integration test and maybe some bike shedding on the export name.

I think "view hierarchy" isn't that descriptive of what it does and just describes our internal naming!

@Lms24
Copy link
Copy Markdown
Member

Lms24 commented Mar 30, 2026

I think "View Hierarchy" already has precedence since the mobile SDKs already ship it like this (e.g. React Native) and it's what the feature is called in the Sentry UI. Do you have other ideas? I could see going with something more DOM or component-related but from my PoV, View Hierarchy is also fine.

@timfish timfish marked this pull request as ready for review April 5, 2026 21:29
cursor[bot]

This comment was marked as outdated.

@timfish timfish requested a review from Lms24 April 5, 2026 22:10
return {
name: 'ViewHierarchy',
processEvent: (event, hint) => {
if (options.shouldAttach?.(event, hint) === false) {
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.

m: Let's only run this event processor for error events. I checked and view hierarchy is only shown on issue detail pages. Mobile SDKs also only add view hierarchy attachments to errors.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Test uses unreliable deprecated envelope helper
    • Replaced deprecated getMultipleSentryEnvelopeRequests and envelopeParser with waitForErrorRequest and properFullEnvelopeRequestParser for reliable test execution.

Create PR

Or push these changes by commenting:

@cursor push 5816421e75
Preview (5816421e75)
diff --git a/dev-packages/browser-integration-tests/suites/integrations/viewHierarchy/test.ts b/dev-packages/browser-integration-tests/suites/integrations/viewHierarchy/test.ts
--- a/dev-packages/browser-integration-tests/suites/integrations/viewHierarchy/test.ts
+++ b/dev-packages/browser-integration-tests/suites/integrations/viewHierarchy/test.ts
@@ -1,7 +1,7 @@
 import { expect } from '@playwright/test';
 import type { ViewHierarchyData } from '@sentry/core';
 import { sentryTest } from '../../../utils/fixtures';
-import { getMultipleSentryEnvelopeRequests, envelopeParser } from '../../../utils/helpers';
+import { properFullEnvelopeRequestParser, waitForErrorRequest } from '../../../utils/helpers';
 
 sentryTest('Captures view hierarchy as attachment', async ({ getLocalTestUrl, page }) => {
   const bundle = process.env.PW_BUNDLE;
@@ -11,19 +11,22 @@
 
   const url = await getLocalTestUrl({ testDir: __dirname });
 
-  const [, events] = await Promise.all([
-    page.goto(url),
-    getMultipleSentryEnvelopeRequests<ViewHierarchyData>(
-      page,
-      1,
-      {},
-      req => envelopeParser(req)?.[4] as ViewHierarchyData,
-    ),
-  ]);
+  const req = await Promise.all([page.goto(url), waitForErrorRequest(page)]).then(([, req]) => req);
 
-  expect(events).toHaveLength(1);
-  const event: ViewHierarchyData = events[0];
+  const envelope = properFullEnvelopeRequestParser(req);
+  const items = envelope[1];
 
+  expect(items).toHaveLength(2);
+
+  const attachmentHeader = items[1][0];
+  expect(attachmentHeader.type).toBe('attachment');
+  expect(attachmentHeader.filename).toBe('view-hierarchy.json');
+
+  const attachmentData = items[1][1];
+  const event: ViewHierarchyData = JSON.parse(
+    typeof attachmentData === 'string' ? attachmentData : new TextDecoder().decode(attachmentData as Uint8Array),
+  );
+
   expect(event.rendering_system).toBe('DOM');
   expect(event.positioning).toBe('absolute');
   expect(event.windows).toHaveLength(2);

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6649760. Configure here.

@timfish timfish merged commit efaf6cf into develop Apr 13, 2026
470 of 476 checks passed
@timfish timfish deleted the timfish/feat/browser-view-hierarchy branch April 13, 2026 19:52
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.

3 participants