From 7f06fe1017450dea1fd762df34d77329401afee7 Mon Sep 17 00:00:00 2001 From: Abdelrahman Awad Date: Mon, 13 Apr 2026 14:24:50 -0400 Subject: [PATCH] fix(nextjs): skip custom browser tracing setup for bot user agents Expose isBotUserAgent from the browser tracing integration and use it in the Next.js wrapper so bot user agents also skip the Next.js-specific router instrumentation path. This is the smallest change to validate the fix. Longer term, we probably want a more general mechanism for integrations to skip their own setup and make that skip decision easy to downstream through wrappers and variants. Co-Authored-By: GPT-5.4 --- .../src/index.bundle.tracing.logs.metrics.ts | 1 + ...le.tracing.replay.feedback.logs.metrics.ts | 1 + .../index.bundle.tracing.replay.feedback.ts | 1 + ...ndex.bundle.tracing.replay.logs.metrics.ts | 1 + .../src/index.bundle.tracing.replay.ts | 1 + packages/browser/src/index.bundle.tracing.ts | 1 + packages/browser/src/index.ts | 1 + .../src/tracing/browserTracingIntegration.ts | 4 ++-- .../src/client/browserTracingIntegration.ts | 6 ++++- packages/nextjs/test/clientSdk.test.ts | 22 +++++++++++++++++++ 10 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/browser/src/index.bundle.tracing.logs.metrics.ts b/packages/browser/src/index.bundle.tracing.logs.metrics.ts index d10bfea67687..0c5c4c0a81cd 100644 --- a/packages/browser/src/index.bundle.tracing.logs.metrics.ts +++ b/packages/browser/src/index.bundle.tracing.logs.metrics.ts @@ -22,6 +22,7 @@ export { export { browserTracingIntegration, + isBotUserAgent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan, } from './tracing/browserTracingIntegration'; diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts index 6caef09459ae..5fb7c306cc87 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts @@ -22,6 +22,7 @@ export { export { browserTracingIntegration, + isBotUserAgent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan, } from './tracing/browserTracingIntegration'; diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.ts index dbff7b4dd7b3..9d9098b5be3d 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.ts @@ -27,6 +27,7 @@ export { export { browserTracingIntegration, + isBotUserAgent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan, } from './tracing/browserTracingIntegration'; diff --git a/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts b/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts index 9972cd85ca8a..a000d456360b 100644 --- a/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts +++ b/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts @@ -22,6 +22,7 @@ export { export { browserTracingIntegration, + isBotUserAgent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan, } from './tracing/browserTracingIntegration'; diff --git a/packages/browser/src/index.bundle.tracing.replay.ts b/packages/browser/src/index.bundle.tracing.replay.ts index f95e3d6cdcc9..496aacf348b9 100644 --- a/packages/browser/src/index.bundle.tracing.replay.ts +++ b/packages/browser/src/index.bundle.tracing.replay.ts @@ -27,6 +27,7 @@ export { export { browserTracingIntegration, + isBotUserAgent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan, } from './tracing/browserTracingIntegration'; diff --git a/packages/browser/src/index.bundle.tracing.ts b/packages/browser/src/index.bundle.tracing.ts index 38186b3aded2..64126c101189 100644 --- a/packages/browser/src/index.bundle.tracing.ts +++ b/packages/browser/src/index.bundle.tracing.ts @@ -28,6 +28,7 @@ export { export { browserTracingIntegration, + isBotUserAgent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan, } from './tracing/browserTracingIntegration'; diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 25415f99894f..3953f91aeca2 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -36,6 +36,7 @@ export { getFeedback, sendFeedback } from '@sentry-internal/feedback'; export { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './tracing/request'; export { browserTracingIntegration, + isBotUserAgent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan, } from './tracing/browserTracingIntegration'; diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index 7eb87cd1d833..23436b34ed58 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -62,7 +62,7 @@ export const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing'; const BOT_USER_AGENT_RE = /Googlebot|Google-InspectionTool|Storebot-Google|Bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Facebot|facebookexternalhit|LinkedInBot|Twitterbot|Applebot/i; -function _isBotUserAgent(): boolean { +export function isBotUserAgent(): boolean { const nav = WINDOW.navigator as Navigator | undefined; if (!nav?.userAgent) { return false; @@ -405,7 +405,7 @@ export const browserTracingIntegration = ((options: Partial void); let lastInteractionTimestamp: number | undefined; diff --git a/packages/nextjs/src/client/browserTracingIntegration.ts b/packages/nextjs/src/client/browserTracingIntegration.ts index ab9ee6c43748..cd957d1d62b5 100644 --- a/packages/nextjs/src/client/browserTracingIntegration.ts +++ b/packages/nextjs/src/client/browserTracingIntegration.ts @@ -1,5 +1,5 @@ import type { Integration } from '@sentry/core'; -import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/react'; +import { browserTracingIntegration as originalBrowserTracingIntegration, isBotUserAgent } from '@sentry/react'; import { nextRouterInstrumentNavigation, nextRouterInstrumentPageLoad } from './routing/nextRoutingInstrumentation'; /** @@ -29,6 +29,10 @@ export function browserTracingIntegration( return { ...browserTracingIntegrationInstance, afterAllSetup(client) { + if (isBotUserAgent()) { + return; + } + // We need to run the navigation span instrumentation before the `afterAllSetup` hook on the normal browser // tracing integration because we need to ensure the order of execution is as follows: // Instrumentation to start span on RSC fetch request runs -> Instrumentation to put tracing headers from active span on fetch runs diff --git a/packages/nextjs/test/clientSdk.test.ts b/packages/nextjs/test/clientSdk.test.ts index b6c62303f0bf..873aa5a2511e 100644 --- a/packages/nextjs/test/clientSdk.test.ts +++ b/packages/nextjs/test/clientSdk.test.ts @@ -19,6 +19,7 @@ Object.defineProperty(global, 'addEventListener', { value: () => undefined, writ const originalGlobalDocument = WINDOW.document; const originalGlobalLocation = WINDOW.location; +const originalNavigator = WINDOW.navigator; // eslint-disable-next-line @typescript-eslint/unbound-method const originalGlobalAddEventListener = WINDOW.addEventListener; @@ -26,6 +27,7 @@ afterAll(() => { // Clean up JSDom Object.defineProperty(WINDOW, 'document', { value: originalGlobalDocument }); Object.defineProperty(WINDOW, 'location', { value: originalGlobalLocation }); + Object.defineProperty(WINDOW, 'navigator', { value: originalNavigator, writable: true, configurable: true }); Object.defineProperty(WINDOW, 'addEventListener', { value: originalGlobalAddEventListener }); }); @@ -43,6 +45,7 @@ describe('Client init()', () => { getIsolationScope().clear(); getCurrentScope().clear(); getCurrentScope().setClient(undefined); + Object.defineProperty(WINDOW, 'navigator', { value: originalNavigator, writable: true, configurable: true }); }); it('inits the React SDK', () => { @@ -160,6 +163,25 @@ describe('Client init()', () => { // @ts-expect-error Test setup for build-time flag delete globalThis.__SENTRY_TRACING__; }); + + it("doesn't run Next.js router instrumentation for bot user agents", () => { + Object.defineProperty(WINDOW, 'navigator', { + value: { + userAgent: 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', + }, + writable: true, + configurable: true, + }); + + const setIntervalSpy = vi.spyOn(globalThis, 'setInterval'); + + init({ + dsn: TEST_DSN, + tracesSampleRate: 1.0, + }); + + expect(setIntervalSpy).not.toHaveBeenCalled(); + }); }); });