Attributing real-user performance issues

Field data tells you that a page is slow or unstable; it rarely tells you why. Lab tools like Lighthouse are better at diagnosing causes, but they only see what happens at initial page load. They miss layout shifts triggered by scrolling or interactions that only occur when a user clicks. That leaves a gap: how do you capture debug information for Core Web Vitals from real users?

Several browser APIs expose the attribution data you need to close that gap — for CLS, LCP, and INP. With this data, you can identify which elements are responsible for poor metrics in the field and prioritize fixes based on actual user impact.

Collecting debug data per metric

Cumulative Layout Shift

CLS is measured across the full page lifecycle, which means user behavior — how far they scroll, what they click — directly affects which elements shift. A lab test that doesn't exercise interactive content will often report far lower CLS than field data does, and that divergence is expected.

To find out which elements are shifting in the real world, use the LayoutShiftAttribution interface. It's exposed on every layout-shift entry emitted by the Layout Instability API, and it tells you which elements shifted and by how much.

You probably don't want to send every shift to your analytics backend to avoid noise. Instead, track all shifts as they occur, but only report on the worst one when you're ready to send the CLS value. The largest source element from the largest shift is the most actionable data point. If you aggregate that element across all users, you'll build a list of shifting elements that affect the most people — and those are the ones to fix first.

Along with the element, capture the time of the largest shift and the URL path at that moment, particularly for single-page applications where the URL may change dynamically.

Largest Contentful Paint

For LCP, the key piece of debug information is which element was the LCP candidate on a given page load. The element can vary widely between users, even on the same page, due to different screen resolutions, scroll positions at load time (for example, from fragment links or text fragments), or personalized content. You can't reliably assume which element will be the LCP candidate — you have to measure it.

The Largest Contentful Paint API reports largest-contentful-paint entries. The element property of the most recent entry gives you the current LCP candidate. Send that element alongside the metric value. It may also help to include LCP sub-part times, so you can determine which specific optimization steps (for example, faster resource load vs. faster rendering) are relevant for your site.

Interaction to Next Paint

INP captures the full latency of an interaction, including event listener execution time and the time to paint the next frame afterward. To debug slow INP in the field, you need to know:

  1. Which element was interacted with
  2. What type of interaction it was
  3. When it occurred (relative to page load)

Slow interactions are frequently caused by a blocked main thread during script loading. If slow interactions cluster around initial load, that points to JavaScript delivery and execution as the problem. Knowing the target elements of slow interactions helps you identify which UI components need optimization. The INP entry includes the target element and timestamp, so you can log both when the entry fires.

Using the web-vitals attribution build

Since version 3, the web-vitals library offers an attribution build that surfaces all of these debug signals, plus additional metadata. The library handles discovery of the INP entry and phases, so you don't have to implement that logic yourself.

With the attribution build, you can construct a debug string and send it as an event parameter (or custom dimension) to your analytics tool. This works with Google Analytics and the pattern transfers to other analytics platforms. For INP, useful signals include the interaction target, interaction type, load state, phase timings, and Long Animation Frame data. Consult the web-vitals attribution documentation for the full list of available signals.

Aggregating the data to find patterns

With both metric values and debug information flowing into your analytics, aggregate the data across users rather than investigating one-off reports. The goal is not to fix every edge case — it's to find the issues that affect the largest number of users, because those will have the most impact on your Core Web Vitals scores at the 75th percentile. Once you fix the root causes behind the most common problematic elements and interactions, your metrics will improve on their own.

Putting Debug Data to Work

The same APIs and web-vitals library techniques that surface individual field diagnostics scale beyond the Core Web Vitals. Any metric that JavaScript can measure in a browser session is fair game for the same approach: attach contextual payloads during the event loop, send them to your backend alongside the timing data, and map click-level symptoms back to page-level diagnostics.

Starting Points and Vendor Responsibilities

For teams already invested in Google Analytics and just beginning to measure performance, the Web Vitals Report tool offers a lower-friction entry point. It natively handles reporting debug information for the Core Web Vitals metrics, so you can get visibility without assembling a custom pipeline first.

Analytics vendors have a larger opportunity here. The techniques described in this guide are intentionally general, but they shouldn't be treated as a complete ceiling for what a debugging-aware analytics product can do. Individual tools are well positioned to capture additional context specific to their instrumentation, their users' traffic patterns, and the deeper layers of a page's runtime behavior.

Closing the Loop

If the existing browser APIs still leave blind spots for your nightly or production debugging workflows, the Chromium team wants specifics. Feature gaps you hit while trying to diagnose Core Web Vitals in the field should be reported to [email protected] alongside your reproduction details and the diagnostic context you were missing.