Skip to content

Conversation

Lms24
Copy link
Member

@Lms24 Lms24 commented Sep 18, 2025

This PR adds new functionality to browserTracingIntegration: By setting the new enableReportPageLoaded option to true, users can take full control* of the pageload span duration. It will stay active until Sentry.reportPageLoaded() is called*. This new functionality is opt-in and nothing changes for the default idle span mechanism.

* there are a couple of caveats and implications to this behaviour:

  • the pageload span is still started as an idle span and finalTimeout still acts as a safeguard to end the pageload span if the final timeout (30s by default) is reached. Just like by default, the span will be ended after the final timeout and the ending reason is set to 'finalTimeout'.
  • by default, the pageload span's end time stamp is trimmed to the end time of the longest running child span. This no longer applies when users set enableReportPageLoaded: true. In this case, the pageload span's end time stamp or duration will not be adjusted.
  • if a new navigation span is started, the pageload span is ended with ending reason 'cancelled'. My reasoning for this behaviour is that the entire SDK behaviour relies on the navigation span being another root span (with the exception of redirects). Ending the pageload span manually is already quite hard, so I'd argue we leave it at this for now and revisit potentially on request.

Usage

Sentry.init({
  integrations: [Sentry.browserTracingIntegration({ enableReportPageLoaded: true })],
  tracesSampleRate: 1,
  // ...
});

// whenever you define the end of your pageload, call
Sentry.reportPageLoaded();

Reviewers, happy to chat about the decisions and also happy to hear better suggestions!

Out of scope: Navigation spans

With this PR we don't provide users an API to control navigation span ending in the same way and I'd suggest we leave it this way for the time being. The reason is that a pageload is started once (at SDK init time) automatically and therefore, users only need to control the end time of this one span. Which IMHO is already hard enough to get right.

If we throw navigation spans into the mix we're in a bit of a weird state where the SDK takes care of automatically starting spans repeatedly, but hands down the responsibility to end them to users. I would argue that for users interested in taking control over the navigation span, too, the more fitting use case is to also start them like so:

Sentry.init({
  dsn: 'https://[email protected]/1337',
  integrations: [Sentry.browserTracingIntegration({ enableReportPageLoaded: true, instrumentNavigation: false })],
  tracesSampleRate: 1,
  debug: true,
});

// Whenever you consider the page loaded
Sentry.reportPageLoaded();

const navigationSpan = Sentry.startBrowserTracingNavigationSpan(Sentry.getClient(), { name: 'custom_navigation' });
// whenever you're ready:
navigationSpan.end();

The missing piece here is an option to control idling behavior but we can adjust this on demand and perhaps pass down the newly introduced trimIdleSpanEndTimestamp to startBrowserTracingNavigationSpan.

closes #14810

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

github-actions bot commented Sep 18, 2025

size-limit report 📦

Path Size % Change Change
@sentry/browser 24.23 kB - -
@sentry/browser - with treeshaking flags 22.74 kB - -
@sentry/browser (incl. Tracing) 40.34 kB +0.23% +89 B 🔺
@sentry/browser (incl. Tracing, Replay) 78.72 kB +0.13% +100 B 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 68.38 kB +0.15% +100 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 83.39 kB +0.13% +104 B 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 95.59 kB +0.1% +94 B 🔺
@sentry/browser (incl. Feedback) 40.95 kB - -
@sentry/browser (incl. sendFeedback) 28.88 kB - -
@sentry/browser (incl. FeedbackAsync) 33.8 kB - -
@sentry/react 25.94 kB - -
@sentry/react (incl. Tracing) 42.32 kB +0.19% +78 B 🔺
@sentry/vue 28.72 kB - -
@sentry/vue (incl. Tracing) 42.14 kB +0.21% +87 B 🔺
@sentry/svelte 24.25 kB - -
CDN Bundle 25.74 kB - -
CDN Bundle (incl. Tracing) 40.16 kB +0.28% +109 B 🔺
CDN Bundle (incl. Tracing, Replay) 76.38 kB +0.15% +111 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 81.88 kB +0.14% +107 B 🔺
CDN Bundle - uncompressed 75.23 kB - -
CDN Bundle (incl. Tracing) - uncompressed 118.89 kB +0.26% +297 B 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 234.01 kB +0.13% +297 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 246.78 kB +0.13% +297 B 🔺
@sentry/nextjs (client) 44.34 kB +0.23% +99 B 🔺
@sentry/sveltekit (client) 40.76 kB +0.21% +85 B 🔺
@sentry/node-core 49.96 kB - -
@sentry/node 152.17 kB - -
@sentry/node - without tracing 91.86 kB +0.01% +1 B 🔺
@sentry/aws-serverless 105.31 kB - -

View base workflow run

Copy link
Contributor

github-actions bot commented Sep 18, 2025

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 8,913 - 8,789 +1%
GET With Sentry 1,325 15% 1,325 -
GET With Sentry (error only) 5,848 66% 6,033 -3%
POST Baseline 1,159 - 1,158 +0%
POST With Sentry 495 43% 492 +1%
POST With Sentry (error only) 1,033 89% 969 +7%
MYSQL Baseline 3,253 - 3,204 +2%
MYSQL With Sentry 406 12% 409 -1%
MYSQL With Sentry (error only) 2,634 81% 2,618 +1%

View base workflow run

* A hook for the browser tracing integrations to trigger the end of a page load span.
* @returns {() => void} A function that, when executed, removes the registered callback.
*/
public on(hook: 'endPageloadSpan', callback: () => void): () => void;
Copy link
Member Author

Choose a reason for hiding this comment

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

I decided to go with the client hooks approach instead of exposing a method on browserTracingIntegration because in contrast to all other integrations, we don't hide the specific implementation of browserTracingIntegration behind defineIntegration. So adding a method would indeed be public API (we also can't introduce defineIntegration now as that would be a breaking change).

Copy link
Member

Choose a reason for hiding this comment

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

IMHO this is a nice enough API for this anyhow, I like it!

@Lms24 Lms24 requested review from mydea and s1gr1d September 18, 2025 15:48
@Lms24 Lms24 self-assigned this Sep 18, 2025
@Lms24 Lms24 force-pushed the lms/feat-browser-reportPageLoaded-ii branch from 3623454 to c1762f1 Compare September 19, 2025 07:23
Copy link
Member

@mydea mydea left a comment

Choose a reason for hiding this comment

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

name nit maybe, but also no strong opinion either way - overall this is really nice, love to finally see this!

Copy link
Member

@s1gr1d s1gr1d left a comment

Choose a reason for hiding this comment

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

I like this :)

Was thinking about renaming the option to enableManualPageLoadEnd or something different including the word manual but enableReportPageLoaded is actually nice because it resembles the actual API you need to call.

@Lms24 Lms24 enabled auto-merge (squash) September 19, 2025 12:53
@Lms24 Lms24 merged commit c123105 into develop Sep 19, 2025
367 of 370 checks passed
@Lms24 Lms24 deleted the lms/feat-browser-reportPageLoaded-ii branch September 19, 2025 15:33
@alt1o
Copy link

alt1o commented Sep 22, 2025

That's great!! I'm just looking for this feature. Wonder when this will release.

@s1gr1d
Copy link
Member

s1gr1d commented Sep 24, 2025

It was released in 10.13.0 :)

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.

Programatic way to indicate that a pageload / navigation transaction has completed
4 participants