77 SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ,
88} from '@sentry/core' ;
99import { startBrowserTracingNavigationSpan , startBrowserTracingPageLoadSpan , WINDOW } from '@sentry/react' ;
10+ import type { RouteManifest } from '../../config/manifest/types' ;
1011import { maybeParameterizeRoute } from './parameterization' ;
1112
1213export const INCOMPLETE_APP_ROUTER_INSTRUMENTATION_TRANSACTION_NAME = 'incomplete-app-router-transaction' ;
@@ -33,20 +34,66 @@ let navigationRoutingMode: 'router-patch' | 'transition-start-hook' = 'router-pa
3334
3435const currentRouterPatchingNavigationSpanRef : NavigationSpanRef = { current : undefined } ;
3536
37+ /**
38+ * Check if the current route is an ISR/SSG page by looking it up in the route manifest
39+ */
40+ function isIsrSsgRoute ( pathname : string ) : boolean {
41+ const globalWithManifest = GLOBAL_OBJ as typeof GLOBAL_OBJ & {
42+ _sentryRouteManifest ?: string | RouteManifest ;
43+ } ;
44+
45+ const manifestData = globalWithManifest . _sentryRouteManifest ;
46+ if ( ! manifestData ) {
47+ return false ;
48+ }
49+
50+ let manifest : RouteManifest ;
51+ if ( typeof manifestData === 'string' ) {
52+ try {
53+ manifest = JSON . parse ( manifestData ) ;
54+ } catch {
55+ return false ;
56+ }
57+ } else {
58+ manifest = manifestData ;
59+ }
60+
61+ if ( ! manifest . isrRoutes || manifest . isrRoutes . length === 0 ) {
62+ return false ;
63+ }
64+
65+ // Check if the pathname matches any ISR route
66+ // For dynamic routes, we need to match the parameterized pattern
67+ const parameterizedPath = maybeParameterizeRoute ( pathname ) ;
68+ const pathToCheck = parameterizedPath || pathname ;
69+
70+ return manifest . isrRoutes . includes ( pathToCheck ) ;
71+ }
72+
3673/** Instruments the Next.js app router for pageloads. */
3774export function appRouterInstrumentPageLoad ( client : Client ) : void {
3875 const parameterizedPathname = maybeParameterizeRoute ( WINDOW . location . pathname ) ;
3976 const origin = browserPerformanceTimeOrigin ( ) ;
40- startBrowserTracingPageLoadSpan ( client , {
41- name : parameterizedPathname ?? WINDOW . location . pathname ,
42- // pageload should always start at timeOrigin (and needs to be in s, not ms)
43- startTime : origin ? origin / 1000 : undefined ,
44- attributes : {
45- [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] : 'pageload' ,
46- [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.pageload.nextjs.app_router_instrumentation' ,
47- [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : parameterizedPathname ? 'route' : 'url' ,
77+
78+ // Check if this is an ISR/SSG page
79+ // if so, don't use cached trace meta tags to prevent using cached trace data
80+ const isIsrSsgPage = isIsrSsgRoute ( WINDOW . location . pathname ) ;
81+
82+ startBrowserTracingPageLoadSpan (
83+ client ,
84+ {
85+ name : parameterizedPathname ?? WINDOW . location . pathname ,
86+ // pageload should always start at timeOrigin (and needs to be in s, not ms)
87+ startTime : origin ? origin / 1000 : undefined ,
88+ attributes : {
89+ [ SEMANTIC_ATTRIBUTE_SENTRY_OP ] : 'pageload' ,
90+ [ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : 'auto.pageload.nextjs.app_router_instrumentation' ,
91+ [ SEMANTIC_ATTRIBUTE_SENTRY_SOURCE ] : parameterizedPathname ? 'route' : 'url' ,
92+ } ,
4893 } ,
49- } ) ;
94+ // For ISR/SSG pages, pass empty trace data to prevent using cached meta tags
95+ isIsrSsgPage ? { sentryTrace : undefined , baggage : undefined } : undefined ,
96+ ) ;
5097}
5198
5299interface NavigationSpanRef {
0 commit comments