Skip to content
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

LCP Element missing from attribution data #563

Open
darlinge opened this issue Nov 6, 2024 · 8 comments
Open

LCP Element missing from attribution data #563

darlinge opened this issue Nov 6, 2024 · 8 comments

Comments

@darlinge
Copy link

darlinge commented Nov 6, 2024

Using the web-vitals library with the attribution build (reportAllChanges set to true),
I've encountered several scenarios where the LCP Element is reported as a null or blank value,
while the LCP URL is a valid image and the Chrome DevTools shows a valid LCP Element in the Performance Panel.
(The LCP Element from the Performance Panel is clickable but does nothing)
These scenarios are all normal page navigations using Chrome 130.0.6723.93 and the latest version of the web-vitals library.

From a data collection standpoint the web-vitals library reports a valid LCP, and a valid LCP URL for the image, but the LCP Element is reported as null or blank. I'm suspecting something with the page framework (this example uses Angular) that might interfere with the web-vitals library accessing the element. But the Chrome DevTools Performance Panel is able to report the LCP Element correctly.

Additionally I've checked the Web Vitals Chrome Extension, which also reports the LCP Element as null or blank.

One working and consistent example (as of November 6th 2024) is the website https://www.kay.com/
I've attached screenshots showing the LCP Element reporting a blank value, with the LCP URL as an image.

kay_lcp_issue1
kay_lcp_issue2

@tunetheweb
Copy link
Member

I think this is a duplicate of #561 where the LCP element is removed (e.g. after a soft navigation to another page), and then only reported upon later (where the reference no longer exists hence why it's blank).

Could you test out #562 to confirm this is fixed there? The node will still not be available (as it does not exist), but the selector should be.

@mmocny
Copy link
Member

mmocny commented Nov 6, 2024

Is this a coincidence or did a recent release somehow make this happen more often?

@darlinge
Copy link
Author

darlinge commented Nov 6, 2024

https://web.dev/articles/lcp#what-elements-are-considered

An element with a background image loaded using the url() function, (as opposed to a CSS gradient)

Adding a note here that the example above is a background image using the url() function

kay_lcp_issue3

@darlinge
Copy link
Author

darlinge commented Nov 6, 2024

Tested #562 using the web-vitals.attribution.iife.js
Still seeing a blank value for LCP Element

kay_lcp_issue_web_vitals_fixed

@tunetheweb
Copy link
Member

Ah I think this is a separate (but related) issue that we can't work around.

This due to Angular's destructive hydration where it re-renders the full DOM (and therefore destroys the element after it was recognised as LCP, but before that LCP entry was sent to web-vitals). It then recreates the page with basically the same, but new, elements. As they are no bigger, the replaced LCP element is not re-emitted as an LCP element with a later timestamp (which is good as you don't get a later LCP, but bad as we don't get a new LCP event with the link to the new DOM node to report).

Therefore once the LCP event is emitted by the browser, the node is already gone, and the web-vitals library can't grab the node details between it getting the event and reporting it (which is what #562 is supposed to make better).

You can see this is the case as if you block the https://www.kay.com/scripts/main.59eab3ae2cc715d9.js request in the Network panel (so the Angular app doesn't load), then web-vitals works fine.

There is not anything the library can do about this, so you're left with a few choices:

  • The easiest is to accept this and for you to fallback to the URL (which thankfully IS saved) in these cases.
  • The latest version of Angular supports on-destructive hydration, which allows you to avoid this issue (and save the performance cost of recreating the entire DOM when the angular code kicks in).
  • @mmocny has done some investigations on Chrome creating the node selectors and keeping that around, and reporting that when the full node is no longer available. However that's still at a proposal stage so will take some time (if it even happens at all!)

@mmocny I guess this answers your question as to whether this is "a coincidence or did a recent release somehow make this happen more often?". It's a coincidence that we had two issues raised for this long-standing problem. And we can only work around this so much in the library!

@mmocny
Copy link
Member

mmocny commented Nov 7, 2024

FWIW the node selector thing was for Event Timing. Makes sense that we want this for element timing as well, but that wasn't actually proposed before (afaik).

@darlinge
Copy link
Author

darlinge commented Nov 7, 2024

Thank you for the detailed explanation @tunetheweb
This does make sense regarding the Angular framework, and we can verify this behavior from the Performance Timeline.

kay_lcp_issue_perf

Would it be possible to re-emit the LCP Event in these situations, which could report the existence of the LCP Element but keep the initial LCP timings?

Also is there anything we can do to capture this LCP Element with third party JS code on the page?

@tunetheweb
Copy link
Member

tunetheweb commented Nov 18, 2024

Would it be possible to re-emit the LCP Event in these situations, which could report the existence of the LCP Element but keep the initial LCP timings?

The problem is that this is a separate element. It is not related to the previous element. So 1) we do not re-emit elements if they are the same size or less and 2) we cannot link them even if we did reemit them. All in all the risk of breaking LCP just to fix attribution is too great here. We need the fixes in spec/browser code discussed in #563 (comment) to solve this.

Also is there anything we can do to capture this LCP Element with third party JS code on the page?

The fix in #561 is likely our best option here. It won't be perfect as it's still possible for the Performance Observer entry to be emitted after the element has been removed, but should cover most cases.

The other option would be for you to hold your own reference to the LCP elements and use that instead.

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

No branches or pull requests

3 participants