Skip to content

nextjs pageload transactions should exclude <Link/> prefetch #18175

@karlkeefer

Description

@karlkeefer

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nextjs

SDK Version

10.25.0

Framework Version

Next 15.5.4 (app router, webpack bundler)

Link to Sentry event

event -- this particular trace is from SDK 10.14.0 but the issue exists on latest release, too.

Reproduction Example/SDK Setup

Basically normal configuration...

    Sentry.init({
      dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
      environment: process.env.NEXT_PUBLIC_SENTRY_ENV,
      release: process.env.NEXT_PUBLIC_SENTRY_RELEASE,
      tracesSampleRate: Number(process.env.NEXT_PUBLIC_SENTRY_SAMPLE_RATE),
      tracePropagationTargets: [
        `^${process.env.NEXT_PUBLIC_BACKEND_URL}/api`, // regex to match backend for distributed tracing
        `^${process.env.NEXT_PUBLIC_HAVEN_URL}`, // regex to match haven for distributed tracing
      ],
      sendDefaultPii: false,
    });

Steps to Reproduce

You can make an app router page with a <Link> to another page in next 15, and your pageload transactions will start including child spans for ?_rsc prefetches. Note that next doesn't do the prefetch when running the dev server, so you have to run a production build to cause those child spans.

Expected Result

I'd expect prefetch to be excluded from pageload timings because the prefetch happens after the page is rendered and interactive.

Actual Result

The prefetches extend pageload timings, sometimes by multiple seconds (our users often have low bandwidth).
Image

Additional Context

Pageload appears to based on idleTimeout. Child spans are being created well after pageload that keep the pageload transaction open. This leads to significantly broken reporting of nextjs pageload timings.

Excluding ?_rsc spans

I can exclude these spans by configuring the browserTracingIntegration:

  browserTracingIntegration({
    shouldCreateSpanForRequest: (url: string) => {
      // Exclude RSC preloads
      // Note: this also excludes these spans from navigation transactions, but that's an acceptable trade...
      if (url.includes("?_rsc=") || url.includes("&_rsc=")) {
        return false;
      }

      // Create spans for all other requests
      return true;
    },
  }),

...but that has the unfortunate side effect (as noted in the comment) of also excluding them for navigation transactions, for which they are one of the most important spans!

Filtering spans higher in the config

The top-level sentry config provides another hook called beforeSendTransaction that exposes various spans (where we could filter out rsc), but I'm not confident modifying that span array wouldn't break something else. E.g. just poking around I found another property that reference the span count.


Mostly, though, I'd expect the sdk to exclude these prefetch spans without additional configuration, as for most sites their inclusion will distort timing.

Metadata

Metadata

Assignees

No one assigned

    Projects

    Status

    Waiting for: Product Owner

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions