Skip to content

feat(trace-view): Add Server Rendering section to pageload span details - #130769

Merged
s1gr1d merged 3 commits into
masterfrom
sig/ssr-trace-connection
Nov 13, 2026
Merged

s1gr1d merged 3 commits into
masterfrom
sig/ssr-trace-connection

Conversation

@s1gr1d

@s1gr1d s1gr1d commented Nov 11, 2026 •

Copy link
Copy Markdown
Member

A pageload of a static or partially static page can come from HTML that the server rendered earlier for other page loads. The server spans of that render are in another trace.

The new section reads page.server_rendering.type and the cache_origin and server_request span links. It shows which part of the page was reused and which part was rendered for this page load, and links to the trace of each.

The section is behind performance-trace-cache-lifecycle.

"Show Spans" will highlight the dynamic server span within the trace
image

When both parts are in another trace (e.g. the dynamic server part arrived too late):
image

Some trace view example links can be seen in the other PR in the stack: #130771

A pageload of a static or partially static page can come from HTML that
the server rendered earlier for other page loads. The server spans of that
render are in another trace, so users cannot find them from this trace.

The new section reads page.server_rendering.type and the cache_origin and
server_request span links. It shows which part of the page was reused and
which part was rendered for this page load, and links to the trace of each.
It works for every SDK that sets these attributes, whatever the framework.

Move the linked span hook out of the cache lifecycle section, so both
sections use it. The section is behind performance-trace-cache-lifecycle.
@s1gr1d
s1gr1d requested a review from a team as a code owner November 11, 2026 10:39
@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Nov 11, 2026
@s1gr1d

s1gr1d commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 152250c. Configure here.

…uest

Go to span took the first http.server span below the pageload. That can
be an API request of the page. Use the span that the tree moved below
the pageload as the server request of the page.

@nsdeschenes nsdeschenes left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small nits to take a peek at, rest LGTM 🚢

Comment on lines +89 to +94
const cacheOrigin = links?.find(
link => getSpanLinkType(link) === CACHE_ORIGIN_LINK_TYPE
);
const serverRequest = links?.find(
link => getSpanLinkType(link) === SERVER_REQUEST_LINK_TYPE
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can we pull out these calls to getSpanLinkType(link) out of these .find() calls, and assign to a variable then just pass that variable.

Something like:

  const linkType = getSpanLinkType(link)
  const cacheOrigin = links?.find(
    link => linkType === CACHE_ORIGIN_LINK_TYPE
  );
  const serverRequest = links?.find(
    link => linkType === SERVER_REQUEST_LINK_TYPE
  );

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point but your proposed helper does not work as link only exists in the callback. but I'll add a small helper.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh shoot sorry i misread it 🤦

Comment on lines +121 to +124
/** Dashed, because the spans of a reused part are never in this trace. */
const ReusedBlock = styled(Stack)`
border: 1px dashed ${p => p.theme.tokens.border.primary};
`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Looking at the docs, i think you should be able to pass this directly to the border property on the Stack. Though you may need to call useTheme to get the theme value 🤔

This is just part of an effort to maintain the reduction of styled calls throughout the app, if the suggestion doesn't work we can leave as is.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The border prop only renders a solid line but the dashed line is on purpose to give more meaning to "this span is not in this trace". But I can use border=primary and a style prop to override that.

});

return (
<Link to={linkedSpan.to} onClick={linkedSpan.onClick}>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: for pages rendered at runtime and reused for more than ~1.5 days (long/no revalidate), this link opens an empty trace because the query only searches around the pageload start right? Is it worth hiding the link or hinting at it in that case, or are we fine leaving it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'll add a follow-up where we can calculate the render time relibably.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the conventions PR: getsentry/sentry-conventions#799

Find the cache_origin and server_request links with one helper. Draw
the reused block with the Stack border prop. The prop only draws solid
lines, so the dashed style stays as an inline style.
@s1gr1d
s1gr1d merged commit 3760ed5 into master Nov 13, 2026
83 checks passed
@s1gr1d
s1gr1d deleted the sig/ssr-trace-connection branch November 13, 2026 10:20
s1gr1d added a commit that referenced this pull request Nov 13, 2026
… trace (#130771)

Stacked on #130769 

When the server reuses HTML for a page (a static page, or the static
shell of a partially static page), the server spans of that render are
in another trace. Until now, the waterfall showed nothing in their
place, so it looked like instrumentation was missing.

This adds a placeholder row under the document request of each pageload
with `page.server_rendering.type`:

- **No bar on the timeline.** The render can be hours older than the
page load, so the row fills the timeline column with a pattern and the
text "Rendered earlier: not on this timeline".
- **Visible when the pageload is collapsed,** next to the server
request, like a server transaction.

For a fully static page:
https://sentry-4x3dkn58u.sentry.dev/explore/traces/trace/cdf98425fa8746f79352a8394e385f32/?node=sr-85846057874639b8-server-render&timestamp=1794319075

<img width="1375" height="387" alt="image"
src="https://github.com/user-attachments/assets/9023504d-1b83-4f7a-9329-4de0c1b6a766"
/>

For a partially static page:
https://sentry-4x3dkn58u.sentry.dev/explore/traces/trace/d5f46a9d8bc640ca8d72c415f1b9b0a7/?fov=0.19530032969846994%2C71.30445552967653&node=span-9e805f433be01de5&timestamp=1794326348

<img width="1379" height="491" alt="image"
src="https://github.com/user-attachments/assets/a63dddcb-0f7a-49b8-b1fc-54a73f492c82"
/>

This branch was successfully deployed

1 active deployment
Preview — 20bbdc2f Deployed Nov 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants