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(); + }); }); });