You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Implement trace propagation from SSR > Pageload in Next 14 App Router #16388
As a first step, @RulaKhaled and I looked into finding a way to manually enable trace propagation via generateMetadata. In theory this sounds easy but in practise, it seems like NextJS is doing some pretty aggressive caching of metadata. So aggressive that although the function is run on each request, the rendered page still includes the metadata from the prerender at build time. We found a way to disable this caching behaviour but it seems a bit aggressive.
The idea is that users add the meta tag in their root layout so that the tags are applied to each page in their application. To disable the metadata caching, export const dynamic = 'force-dynamic'; needs to be set.
exportconstdynamic='force-dynamic';exportasyncfunctiongenerateMetadata(): Promise<Metadata>{const metaObject ={title: 'Create Next App',description: "Generated by create next app",other: {
...getTraceData()}};returnmetaObject}
After some more research, we concluded that letting users manually set generateMetadata to inject meta tags manually will be the one we take for Next 14 and older.
So what we'll tell users to do, is to add this code to their root layout:
// if they already have a metadata object, they'll need to delete it
- export const metadata = {- title: "my page",- }+ export async function generateMetadata(): Promise<Metadata> {+ return {+ // whatever else they have in here+ title: "my page",+ other: {+ ...Sentry.getTraceData(),+ },+ };+ }
Findings:
There's no need for us to worry about forcing dyanamic rendering via export const dynamic = 'force-dynamic:
We don't want to inject the tags on static pages anyway. getTraceData() already returns undefined values at build time, meaning this doesn't inject anything.
side-note: If we ever want to trace prerender cycles and link them to the pageloads, we can overwrite getTraceData in the NextJS SDK and simply return whatever information the client needs to pick up to establish a span link (cc @s1gr1d)
Users have to think about dynamic vs. static pages themselves to display the "correct" content. They will already define the behaviour on layout (e.g. peated) or page level (e.g. my test app).
generateMetadata is invoked in dynamic pages only, meaning, we get correct meta tags exactly in the pages we want them in.
Tasks:
Update docs (manual setup, set up tracing) and tell users to add this
Update wizard to inject generateMetadata in the root layout or if this already exists, show copy/paste instructions for users to also return the other: {...Sentry.getTraceData()} field
Add/Adjust a Next14 e2e test app with generateMetadata and assert on http.server and pageload transactions being connected by the same trace.
Why not add the headers in our patched generateMetadata?
We discussed this briefly but it seems like there's no need for this, assuming correct setup (i.e. users adding getTraceData values to their setup.
If users have nested generateMetadata calls, the final meta tags are merged by NextJS, so we don't need to patch allgenerateMetadata calls to always add our meta tags
Users still have to export generateMetadata in their root layout so that the Sentry meta tags are injected everywhere they should be. So if we tell them to export it there, we might as well tell them to add the three lines to get Sentry meta tags.
Activity
Lms24 commentedon May 27, 2025
UPDATE: see #16388 (comment)
As a first step, @RulaKhaled and I looked into finding a way to manually enable trace propagation via
generateMetadata. In theory this sounds easy but in practise, it seems like NextJS is doing some pretty aggressive caching of metadata. So aggressive that although the function is run on each request, the rendered page still includes the metadata from the prerender at build time. We found a way to disable this caching behaviour but it seems a bit aggressive.The idea is that users add the meta tag in their root layout so that the tags are applied to each page in their application. To disable the metadata caching,
export const dynamic = 'force-dynamic';needs to be set.Lms24 commentedon May 27, 2025
Update:
After some more research, we concluded that letting users manually set
generateMetadatato inject meta tags manually will be the one we take for Next 14 and older.So what we'll tell users to do, is to add this code to their root layout:
Findings:
export const dynamic = 'force-dynamic:getTraceData()already returns undefined values at build time, meaning this doesn't inject anything.getTraceDatain the NextJS SDK and simply return whatever information the client needs to pick up to establish a span link (cc @s1gr1d)generateMetadatais invoked in dynamic pages only, meaning, we get correct meta tags exactly in the pages we want them in.Tasks:
generateMetadatain the root layout or if this already exists, show copy/paste instructions for users to also return theother: {...Sentry.getTraceData()}fieldgenerateMetadataand assert onhttp.serverandpageloadtransactions being connected by the same trace.Why not add the headers in our patched
generateMetadata?We discussed this briefly but it seems like there's no need for this, assuming correct setup (i.e. users adding
getTraceDatavalues to their setup.generateMetadatacalls, the final meta tags are merged by NextJS, so we don't need to patch allgenerateMetadatacalls to always add our meta tagsgenerateMetadatain their root layout so that the Sentry meta tags are injected everywhere they should be. So if we tell them to export it there, we might as well tell them to add the three lines to get Sentry meta tags.