Skip to content

🐛 Prevent duplicate Next.js RUM views from discarded renders - #4940

Open
BeltranBulbarellaDD wants to merge 10 commits into
mainfrom
beltran.bulbarella/next_js_render_issue
Open

🐛 Prevent duplicate Next.js RUM views from discarded renders#4940
BeltranBulbarellaDD wants to merge 10 commits into
mainfrom
beltran.bulbarella/next_js_render_issue

Conversation

@BeltranBulbarellaDD

@BeltranBulbarellaDD BeltranBulbarellaDD commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Motivation

Fixes #4931.

DatadogAppRouter used to call startNextjsView() while React rendered, with a useRef as its only guard. React may discard and retry an uncommitted render. Each retry gets a new ref, but the RUM side effect from the previous attempt has already escaped:

render attempt 1: useRef(null) -> startView("/user/42") -> discarded
render attempt 2: useRef(null) -> startView("/user/42") -> discarded
render attempt 3: useRef(null) -> startView("/user/42") -> committed

The result is several RUM views with distinct IDs for one displayed page.

Moving that ref to module scope would only hide part of the symptom and would make React state global. It would still perform startView() during render, so an abandoned render could create or rename a view for a route that never committed. React requires render to remain pure; effects run after commit. See React's rule and Synchronizing with Effects.

Approach

We split view creation from view-name normalization:

  1. Initial load: nextjsPlugin.onInit() starts one view immediately, outside React.
  2. Client navigation: Next.js calls onRouterTransitionStart() before React renders. It starts the route-change view at navigation time, preserving loading timing for slow routes. This is the intended role of the Next.js hook.
  3. Committed route: DatadogAppRouter uses useEffect to call setNextjsViewName(). This only turns a concrete path such as /user/42 into /user/[id]; it does not create a view or block paint.
onInit()                          -> startView("/user/42")        initial_load
onRouterTransitionStart("/slow") -> startView("/slow")            route_change, before commit
React commits "/user/42"          -> useEffect -> setViewName("/user/[id]")

This follows the same separation used by PostHog's App Router component: derive route state in render and publish it from useEffect.

Transition deduplication

Next.js can provide an opaque transition event.id when experimental.instrumentationClientRouterTransitionEvents is enabled. The plugin records the last ID and ignores a repeated callback for that same transition. Different IDs remain separate navigation attempts, including redirects. Next creates this ID in startRouterTransition.

Sentry also starts navigation instrumentation from onRouterTransitionStart rather than waiting for React to commit. Its deduplication is specifically for overlap between its legacy router patch and the hook, not repeated hook calls: handler, hook entry point.

Tests

  • Unit: one initial view, view-name normalization, query/hash filtering, and repeated transition-ID deduplication.
  • E2E: discarded initial renders produce one initial_load view.
  • E2E: a slow route starts its view before the route commits.
  • E2E: redirects retain one route-change view per transition.

@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Aug 12, 2026

Copy link
Copy Markdown

Tests

⚠️ Warnings

⚠️ Your PR has warnings. Please review the issues below.

❄️ 1 New flaky test detected

↳ plugin: nextjs › should start a slow navigation view before the route commits from plugins/nextjsPlugin.scenario.ts

View in Flaky Test Management

ℹ️ Info

No other issues found (see more)

🧪 All tests passed

🎯 Code Coverage (details)
Patch Coverage: 76.00%
Overall Coverage: 77.02% (-0.00%)

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: e9c6d7c | Docs | View more details | Give us feedback!

@BeltranBulbarellaDD BeltranBulbarellaDD changed the title test nextjs rendering issue 🐛 Prevent duplicate Next.js RUM views from discarded renders Aug 17, 2026
@BeltranBulbarellaDD
BeltranBulbarellaDD marked this pull request as ready for review August 19, 2026 15:16
@BeltranBulbarellaDD
BeltranBulbarellaDD requested a review from a team as a code owner August 19, 2026 15:16
Comment thread packages/browser-rum-nextjs/src/domain/nextJSRouter/useStartNextjsView.ts Outdated
@sbarrio
sbarrio requested a review from bdibon August 20, 2026 07:06
@BeltranBulbarellaDD
BeltranBulbarellaDD marked this pull request as draft August 27, 2026 09:49
@BeltranBulbarellaDD
BeltranBulbarellaDD removed the request for review from bdibon August 27, 2026 09:49
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 27, 2026

Copy link
Copy Markdown

Bundles Sizes Evolution

📦 Bundle Name Base Size Local Size 𝚫 𝚫% Status
Rum 181.63 KiB 181.63 KiB 0 B 0.00%
Rum Profiler 8.43 KiB 8.43 KiB 0 B 0.00%
Rum Recorder 25.32 KiB 25.32 KiB 0 B 0.00%
Logs 57.93 KiB 57.93 KiB 0 B 0.00%
Rum Salesforce N/A 139.69 KiB N/A N/A N/A
Rum Slim 139.68 KiB 139.68 KiB 0 B 0.00%
Worker 22.96 KiB 22.96 KiB 0 B 0.00%
Rum Shopify N/A 205.99 KiB N/A N/A N/A
Rum-shopify Profiler N/A 8.43 KiB N/A N/A N/A
Rum-shopify Recorder N/A 3.74 KiB N/A N/A N/A

@BeltranBulbarellaDD
BeltranBulbarellaDD marked this pull request as ready for review August 28, 2026 14:11

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31857be6e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/browser-rum-nextjs/src/domain/nextJSRouter/datadogAppRouter.tsx Outdated
Comment thread packages/browser-rum-nextjs/src/domain/nextjsPlugin.ts Outdated
@sbarrio
sbarrio requested a review from bdibon September 1, 2026 07:04
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-08T10:42:56.300966Z e9c6d7c New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 58fc0e9b68

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/browser-rum-nextjs/src/domain/nextjsPlugin.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9e9ab88490

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/browser-rum-nextjs/src/domain/nextjsPlugin.ts
Comment thread packages/browser-rum-nextjs/src/domain/nextjsPlugin.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e9c6d7cfe4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/browser-rum-nextjs/src/domain/nextjsPlugin.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Router components create duplicate RUM views: render-phase startView() guarded only by useRef

2 participants