-
Notifications
You must be signed in to change notification settings - Fork 168
✨ feat: collect LCP subparts RUM-13818 #4104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
All contributors have signed the CLA ✍️ ✅ |
Bundles Sizes Evolution
🚀 CPU Performance
🧠 Memory Performance
|
|
✅ Tests 🎉 All green!❄️ No new flaky tests detected 🎯 Code Coverage 🔗 Commit SHA: e0dd7ee | Docs | Datadog PR Page | Was this helpful? Give us feedback! |
|
I have read the CLA Document and I hereby sign the CLA |
There was a problem hiding this comment.
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: 94434b0253
ℹ️ 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".
| const lcpResourceEntry = resourceUrl | ||
| ? (getResourceEntries()?.find((e) => e.name === resourceUrl) as PerformanceResourceTiming | undefined) | ||
| : undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Match the LCP resource to the correct request
The LCP resource timing is selected via getResourceEntries()?.find((e) => e.name === resourceUrl), which returns the first entry with that URL. Resource entries persist for the whole page and can include multiple requests for the same URL (e.g., preloads, cache-busting reloads, or SPA route changes). In those cases the first entry is often unrelated to the LCP element, so loadDelay/loadTime/renderDelay are computed from stale timings, corrupting the subparts metrics. Consider picking the most recent matching entry whose timing precedes lcpEntry.startTime instead of the first match.
Useful? React with 👍 / 👎.
| const firstByte = getSafeFirstByte(getNavigationEntry()) || (0 as RelativeTime) | ||
| const lcpRequestStart = Math.max(firstByte, lcpResourceEntry?.startTime || 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid reporting subparts when firstByte is invalid
When getSafeFirstByte() returns undefined for negative or future responseStart values (the exact cases it is meant to guard against), the code falls back to 0 and still emits subparts. This will silently report a 0ms TTFB and inflate renderDelay for affected browsers, which is misleading data rather than a safe omission. Consider skipping subParts or leaving firstByte undefined when getSafeFirstByte() fails.
Useful? React with 👍 / 👎.
Motivation
LCP Subparts are values that compute the final LCP measure the browser SDK.
This is helpful for troubleshooting LCP since it help to define what type of LCP issue we are facing (server, render etc.) by looking at the biggest contributor (more details in this doc)
Here is a breakdown of each part :
This PR adds the collection of the LCP subparts when we collect the LCP
Changes
trackLargestContentfulPaintwhen we have an LCP entry :firstByte)subPartsobject that is added in the final payloadfirstBytevaluesubPartsobjectTest instructions
Checklist