Skip to content

feat(browser): Start a navigation span for bfcache restores - #23748

Open
logaretm wants to merge 1 commit into
awad/js-1019-soft-nav-web-vitals-spansfrom
awad/bfcache-navigation-span
Open

feat(browser): Start a navigation span for bfcache restores#23748
logaretm wants to merge 1 commit into
awad/js-1019-soft-nav-web-vitals-spansfrom
awad/bfcache-navigation-span

Conversation

@logaretm

@logaretm logaretm commented Aug 28, 2026

Copy link
Copy Markdown
Member

Starts a navigation span when the page is restored from the back/forward cache.

A restore resurrects the frozen document, so there is no document load and no usable history event: popstate either doesn't fire or is swallowed because the URL is unchanged. Without a span of its own, everything after the restore joins the trace the page had before it was frozen, which misattributes errors and breadcrumbs as much as vitals.

It lives in browserTracingIntegration rather than bfcacheIntegration so it doesn't depend on an opt-in integration being enabled, and carries browser.navigation.type: bfcache since a restore is near-instant and would otherwise drag navigation duration percentiles down with no way to tell it apart.

Stacked on #23425.

@logaretm logaretm changed the title awad/bfcache navigation span feat(browser): Report web vitals for bfcache restores Aug 28, 2026
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from c306449 to 831a206 Compare August 28, 2026 18:39
@logaretm logaretm changed the title feat(browser): Report web vitals for bfcache restores feat(browser): Start a navigation span for bfcache restores Aug 28, 2026
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.81 kB - -
@sentry/browser - with treeshaking flags 27.12 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.01 kB - -
@sentry/browser (incl. Tracing) 50.25 kB +1.99% +976 B 🔺
@sentry/browser (incl. Tracing + Span Streaming) 50.27 kB +2.02% +991 B 🔺
@sentry/browser (incl. Tracing, Profiling) 53.24 kB +1.99% +1.04 kB 🔺
@sentry/browser (incl. Tracing, Replay) 89.78 kB +1.1% +975 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 78.88 kB +1.15% +894 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 94.47 kB +1.05% +978 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 107.46 kB +0.96% +1.02 kB 🔺
@sentry/browser (incl. Feedback) 46.3 kB - -
@sentry/browser (incl. sendFeedback) 33.87 kB - -
@sentry/browser (incl. FeedbackAsync) 38.99 kB - -
@sentry/browser (incl. Metrics) 29.84 kB - -
@sentry/browser (incl. Logs) 30.1 kB - -
@sentry/browser (incl. Metrics & Logs) 30.78 kB - -
@sentry/react 30.57 kB - -
@sentry/react (incl. Tracing) 52.56 kB +1.79% +924 B 🔺
@sentry/vue 36.07 kB - -
@sentry/vue (incl. Tracing) 52.48 kB +1.8% +927 B 🔺
@sentry/svelte 28.85 kB - -
CDN Bundle 30.56 kB - -
CDN Bundle (incl. Tracing) 50.73 kB +1.86% +923 B 🔺
CDN Bundle (incl. Logs, Metrics) 32.83 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 52.7 kB +1.8% +929 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 73.53 kB +0.07% +51 B 🔺
CDN Bundle (incl. Tracing, Replay) 88.28 kB +1.07% +928 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 90.23 kB +1.09% +968 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 94.3 kB +1.1% +1.03 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 96.32 kB +1.1% +1.04 kB 🔺
CDN Bundle - uncompressed 90.47 kB - -
CDN Bundle (incl. Tracing) - uncompressed 151.58 kB +2.17% +3.22 kB 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.04 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 157.54 kB +2.09% +3.22 kB 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 226.45 kB +0.07% +151 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 271.15 kB +1.2% +3.2 kB 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 277.1 kB +1.17% +3.2 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 284.85 kB +1.14% +3.2 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 290.79 kB +1.12% +3.2 kB 🔺
@sentry/nextjs (client) 54.9 kB +1.51% +813 B 🔺
@sentry/sveltekit (client) 50.67 kB +1.92% +950 B 🔺
@sentry/core/server 36.99 kB - -
@sentry/core/browser 13.55 kB - -
@sentry/node 127.95 kB +0.02% +23 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 81.61 kB - -
@sentry/node - without tracing 88.73 kB +0.03% +21 B 🔺
@sentry/node - without channel injection 107.17 kB +0.02% +19 B 🔺
@sentry/aws-serverless 97.12 kB +0.03% +25 B 🔺
@sentry/cloudflare (withSentry) - minified 202.05 kB - -
@sentry/cloudflare (withSentry) 502.91 kB - -

View base workflow run

@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 831a206 to d7cd440 Compare August 31, 2026 16:03
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from d7cd440 to e67604c Compare September 8, 2026 14:56
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from e67604c to 08b4500 Compare September 8, 2026 14:57
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 08b4500 to 62457db Compare September 9, 2026 13:56
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 62457db to 7e4c2bc Compare September 9, 2026 16:06
@logaretm
logaretm marked this pull request as ready for review September 9, 2026 16:08
@logaretm
logaretm requested a review from a team as a code owner September 9, 2026 16:08
@logaretm
logaretm requested review from Lms24 and msonnb and removed request for a team September 9, 2026 16:08

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread packages/browser/test/tracing/browserTracingIntegration.test.ts
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch 2 times, most recently from 48fcffe to b7439e2 Compare September 9, 2026 16:28
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from b7439e2 to 14b181f Compare September 9, 2026 16:40

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread packages/browser/src/tracing/browserTracingIntegration.ts
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 14b181f to 18c743a Compare September 9, 2026 17:09
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 18c743a to 5c7be80 Compare September 9, 2026 17:37
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 5c7be80 to 18ab1ef Compare September 9, 2026 17:52

@cursor cursor Bot left a comment

Copy link
Copy Markdown

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 is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 18ab1ef. Configure here.

Comment thread packages/browser/src/tracing/browserTracingIntegration.ts
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 18ab1ef to 268dcd7 Compare September 9, 2026 19:22
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 268dcd7 to 4568daa Compare September 9, 2026 19:26
Comment on lines +710 to +720
// Deliberately no `startTime`: the span starts now, at the restore. The
// `PerformanceNavigationTiming` entry still describes the original document load and
// would date the span to before the page was frozen.
name: hasSpanStreamingEnabled(client)
? NAVIGATION_SPAN_NAME_FALLBACK
: WINDOW.location?.pathname || '/',
attributes: {
[SENTRY_SEGMENT_NAME_SOURCE]: 'url',
[SENTRY_ORIGIN]: 'auto.navigation.browser.bfcache',
// A bfcache restore is near-instant, so these spans would otherwise drag
// navigation duration percentiles down with no way to tell them apart.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: Multiple Sentry client initializations lead to duplicate pageshow event listeners on the global WINDOW object, causing redundant navigation spans to be created.
Severity: MEDIUM

Suggested Fix

To prevent duplicate listeners, add a guard within the afterAllSetup function to check if the pageshow listener has already been attached to the WINDOW object before adding it. This will ensure that only one listener is active, regardless of how many clients are initialized.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/browser/src/tracing/browserTracingIntegration.ts#L698-L720

Potential issue: Initializing multiple Sentry clients, which can occur in environments
like microfrontends or with hot reloading, causes the `afterAllSetup` hook to run for
each client instance. This hook adds a `pageshow` event listener to the global `WINDOW`
object. Because there is no check to see if a listener has already been attached,
multiple identical listeners accumulate. When a `pageshow` event with `persisted=true`
is fired by the browser, all of these accumulated listeners will execute, resulting in
the creation of duplicate navigation spans for a single user navigation.

Did we get this right? 👍 / 👎 to inform future reviews.

… bfcache

Prototype. A bfcache restore resurrects the frozen document, so there is
no document load and no usable history event: `popstate` either doesn't
fire or is swallowed, because the URL is unchanged from when the page was
frozen. Two independent guards in the existing path suppress it, neither
written with bfcache in mind, so there is no small nudge that gets a span
out of it.

Without one, everything after the restore joins the trace the page had
before it was frozen, separated by however long it sat in the cache. That
misattributes errors, breadcrumbs, clicks and fetches, not just the web
vitals that prompted this.

The span is started from a `pageshow` listener in `browserTracingIntegration`
rather than `bfcacheIntegration`, so it does not depend on an opt-in
integration that is about hit/miss diagnostics. It is gated on
`instrumentNavigation` and on by default.

It carries `browser.navigation.type: bfcache`. A restore is near-instant,
so without a way to filter these out they would drag navigation duration
percentiles down exactly the way bfcache vitals would have dragged LCP.

The span deliberately starts at the `pageshow` event rather than from
`PerformanceNavigationTiming`, which is not replaced on restore and still
describes the original document load.

Known gap, pinned by a test: `bfcacheIntegration` registers its own
`pageshow` listener from `setupOnce`, which core always runs before every
`afterAllSetup`, so its hit/miss metric is emitted before this span exists
and still lands on the pre-freeze trace.
@logaretm
logaretm force-pushed the awad/bfcache-navigation-span branch from 4568daa to 83d3b23 Compare September 9, 2026 19:38
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