Why Lab Results Differ From Real Users

Core Web Vitals—Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS)—are the three metrics Google uses to judge page experience for Search ranking starting June 2021. While that date is close, knowing whether your site actually passes remains tricky. Both PageSpeed Insights and the Core Web Vitals report in Google Search Console draw on the same underlying data, yet they often appear to contradict each other. The reason is that these tools mix two fundamentally different kinds of measurement.

The metrics that count for ranking come from field data, also called Real User Metrics (RUM). Google collects anonymized performance information from Chrome users and publishes it through the Chrome User Experience Report (CrUX). This is the data behind the Search Console report and the field section of PageSpeed Insights.

The other kind of measurement is lab or synthetic testing, as done by Lighthouse. These tools load a page under simulated network and device conditions and report what happened in that one run. A Lighthouse score from a powerful developer machine tells you little about what a visitor on a mid-range Android phone over 4G experiences. LCP depends heavily on network speed and device processing power, and FID is even more tied to how fast the CPU can handle JavaScript and layout work. CLS is less affected by hardware, but it still diverges between lab and field for several reasons:

  • Lab tools typically measure CLS only during page load, while the field metric tracks shifts for the entire life of the page, including those triggered by scrolling or post-load content.
  • The metric depends on viewport size. Mobile and desktop presets in tools do not represent the wide range of actual screen sizes.
  • Users see different content—cookie banners, personalized promotions, ad-blocker states, A/B test variations—which changes what shifts occur.
  • The definition of CLS is still evolving. Chrome has been excluding “invisible” shifts and is working on larger changes to the metric itself, so values can differ across Chrome versions.

Because the same metric names are used for lab approximations and real-world data, the numbers are easy to misinterpret. In particular, Total Blocking Time (TBT) in Lighthouse serves as a proxy for FID, and Time to Interactive (TTI) is also worth watching, but neither is the actual field metric. Some in the performance community have even suggested renaming the lab versions to avoid confusion.

The Lab-RUM Gap

Running Lighthouse on your own machine and getting green scores is no guarantee of a good user experience in the wild. The reverse is also true: a lab test on a heavily throttled connection can look worse than your field data, since Lighthouse's mobile emulation is often more aggressive than what many Western users actually experience. There are ongoing discussions about adjusting Lighthouse mobile settings to narrow this gap.

For a full picture, you need both kinds of data. Lab testing helps you debug and iterate quickly—it isolates issues and verifies fixes under controlled conditions. Field data tells you what your users actually encounter, and it is the only data Google will use for ranking. Monitoring both, and understanding what each can and cannot tell you, is the only way to know whether your optimization efforts are working.

The Older Metrics Still in the Mix

Part of the confusion around Core Web Vitals stems from their coexistence with the metrics teams have relied on for years, particularly those surfaced by tools like PageSpeed Insights. Enter a URL, click Analyze, and within seconds you get two tabs — mobile and desktop — loaded with audit data.

PageSpeed Insights audit for the Smashing Magazine website scoring 96 and passing Core Web Vitals.
Example screenshot of PageSpeed Insights audit (Large preview)

The headline figure here is the Lighthouse performance score out of 100. It has long been a shorthand for overall performance, condensing many signals into one easy number. That goal overlaps with Core Web Vitals, but the score is not a simple summary of the three core metrics. Instead, it currently draws on six weighted metrics:

  • First Contentful Paint (FCP)
  • SpeedIndex (SI)
  • Largest Contentful Paint (LCP)
  • Time to Interactive (TTI)
  • Total Blocking Time (TBT)
  • Cumulative Layout Shift (CLS)

Notably, each metric carries a different weight. CLS, despite being a Core Web Vital, still only accounts for 5% of the score. The practical upshot: a high, green Lighthouse score does not guarantee your pages pass the Core Web Vitals thresholds. You need to look at the three core metrics separately.

Scrolling past the score, PageSpeed Insights shows field data. This section can confuse because it lists FCP alongside the four Core Web Vitals, even though FCP is not one of them. In practice, FCP is often flagged as a warning there even when all three Core Web Vitals pass. When no field data exists for the exact URL, the tool falls back to origin data for the whole domain (hidden by default when URL-level data is available).

The 6 lab metrics measured by PageSpeed Insights: First Contentful Paint (FCP), Time to Interactive (TTI), Speed Index (SI), Total Blocking Time (TBT), Largest Contentful Paint (LCP), and Cumulative Layout Shift (CLS)
PageSpeed Insights lab metrics (Large preview)

Under lab data, you see the six metrics feeding the performance score. LCP and CLS appear here again in their lab versions, marked with a blue label to signal their Core Web Vitals status. The tool also links to a score calculator, letting you experiment with what different metric values would do to the overall score.

PageSpeed Insights runs nearly 50 additional checks grouped as Opportunities and Diagnostics. These do not affect the score or the Core Web Vitals directly, but they are useful pointers for improving performance. The diagnostics are especially handy: they reveal the specific element contributing to LCP and the shifts responsible for CLS, which are exactly what you need when optimizing.

For now, attention is concentrated on the three Core Web Vital metrics, even if the broader Lighthouse score and audits remain useful for tuning. It is quite possible to clear the Core Web Vitals bar while still having room to improve in other Lighthouse areas, so treat the two as complementary rather than interchangeable.

Getting a Site-Wide View

PageSpeed Insights is fine for a single URL or an origin overview, but for a full picture of how Google evaluates your whole site, the place to be is Google Search Console. This free Google product is already familiar to SEO teams, but the kind of work Core Web Vitals issues require means development teams should get access as well. Verification involves the usual steps: proving ownership via a file on your server, a DNS record, or similar methods.

The Core Web Vitals report there summarizes how your site has performed over the last 90 days.

Mobile and Desktop graphs with a varying number of Poor, Needs Improvement and Good URLs over time.
Core Web Vitals Report in Google Search Console (Large preview)

The goal is pages marked green, with no ambers or reds. An amber means you are close but not there — only green counts for the full benefit. A well-considered approach is to fix issues affecting multiple pages at once; this usually shrinks the number of failing URLs to a manageable set where you can decide what really needs attention.

Google is rolling out Core Web Vitals ranking signals on mobile first, and it is reasonable to expect desktop to follow. Ignoring desktop while fixing pages would be a mistake.

Opening one of the report entries drills down to which specific vital is failing, with a sample of affected URLs. Search Console groups URLs by similar issues, letting you address related pages together. From there you can jump to PageSpeed Insights for a quick audit, confirm your fixes bring the lab values in line, and move on to the next cluster.

One recurring frustration appears once you start making changes: the Core Web Vitals report does not reflect them immediately. The graph updates daily, but the numbers barely move even after fixes ship. PageSpeed Insights field data stays stubbornly red as well. The explanation lies in how field data is collected, which is the subject of the next steps in working with these metrics.

How 28 Days of p75 Data Shapes What You See

Field data for the Web Vitals is slow to change because the Chrome User Experience Report (CrUX) is built on the last 28 days of data, and reporting uses only the 75th percentile of that data. Both of these choices are deliberate: they smooth out fluctuations caused by different networks and devices, giving a clearer picture of how your site performs for most users without excess noise.

The trade-off is a sluggish feedback loop. When you fix a performance issue, the results of that fix don't appear in CrUX until the new data makes up enough of that 28-day window. The 75th percentile requirement adds an extra layer of delay that isn't always obvious.

DayLCP28 day Mean28 day p75
Day 0101010
Day 119.6810
Day 219.3610
Day 319.0410
............
Day 2013.5710
Day 2113.2510
Day 2212.931
Day 2312.611
............
Day 2711.321
Day 28111

In that simplified example, your dramatic improvement isn't reflected at all until day 22. Before that point, more than 25% of the 28-day window is still made up of pre-change data, so the p75 value is stuck at the old, higher number. This makes it look like your fixes had no effect at all for weeks.

A mean average, if it were used instead, would show gradual progress starting immediately. That's the trade-off: the p75 methodology filters out extremes completely, which is why near the end of the cycle it can actually produce lower values than a mean would. In practice, this is why Web Vitals graphs often show all pages jumping from failing to passing on the same day.

Graph showing mostly amber, some green and no reds and halfway through the gran there is a sudden switch to all green
Core Web Vitals graph can show large swings (Large preview)

That sudden jump can surprise people expecting gradual, incremental improvements as individual page issues are resolved. It is also common to see Search Console reports hold at amber for a while—even as fixes roll out—before finally shifting to green. This relates directly to how page views are distributed across the threshold values.

This 28-day p75 mechanism explains a lot of the observed lag, though it doesn't account for everything. Some experienced practitioners report significantly longer delays in the Core Web Vitals report than this methodology alone would predict. That leaves you wondering: is the only option to make fixes and wait patiently until CrUX updates?

Watching the Percentages, Not Just the Threshold

Fortunately, there is more signal in the data than a single pass/fail value. PageSpeed Insights shows the percentage of page views in each of the green, amber, and red buckets under the main metric value:

PageSpeed Insights screenshot showing 4 key metrics (FCP, FID, LCP, and CLS) and the percentages of visitors in green, amber and red buckets for each of them.
PageSpeed Insights 4 key metrics. (Large preview)

Take CLS, for example: a p75 value of 0.11 appears in red font since it exceeds the 0.1 threshold, but the page is actually in the amber range—true red starts above 0.25. More importantly, if the green bar sits at 73%, the page is very close to passing once that climbs to 75%. Tracking that percentage over time lets you see momentum before the main p75 value changes. A shift from 73% to 74% signals you're heading in the right direction.

To get more precise figures than the PageSpeed Insights colour bars show, you can use the CrUX API, which is free. After obtaining an API key, you can query it with a simple curl command:

curl -s --request POST 'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=API_KEY' \
    --header 'Accept: application/json' \
    --header 'Content-Type: application/json' \
    --data '{"formFactor":"PHONE","url":"https://www.example.com"}'   

The response returns JSON with exact percentages for each bucket:

{
  "record": {
    "key": {
      "formFactor": "PHONE",
      "url": "https://www.example.com/"
    },
    "metrics": {
      "cumulative_layout_shift": {
        "histogram": [
          {
            "start": "0.00",
            "end": "0.10",
            "density": 0.99959769344240312
          },
          {
            "start": "0.10",
            "end": "0.25",
            "density": 0.00040230655759688886
          },
          {
            "start": "0.25"
          }
        ],
        "percentiles": {
          "p75": "0.00"
        }
      },
      "first_contentful_paint": {
        ...
      }
    }
  },
  "urlNormalizationDetails": {
    "originalUrl": "https://www.example.com",
    "normalizedUrl": "https://www.example.com/"
  }
} 

If you'd rather not set up an API key, you can inspect the same precision inside PageSpeed Insights itself: open DevTools while running a test and look at the XHR call it makes to the CrUX API. An interactive API explorer also allows you to run sample queries without any tooling, though for regular use a key and curl is usually more efficient.

The API can query an origin as well as a URL. Use an origin lookup when an individual URL doesn't show data; the API aggregates all page visits for that domain. PageSpeed Insights uses this fallback, but Google Search Console does not. Google has never stated exactly how the Core Web Vitals will factor into ranking—whether origin-level scores matter, individual URLs only, or whether they apply the same fallback logic as PageSpeed Insights. The closest guidance so far comes from this FAQ answer:

Q: How is a score calculated for a URL that was recently published, and hasn’t yet generated 28 days of data?

A: Similar to how Search Console reports page experience data, we can employ techniques like grouping pages that are similar and compute scores based on that aggregation. This is applicable to pages that receive little to no traffic, so small sites without field data don’t need to be worried.

Monitoring CrUX Directly

For those who want tighter monitoring, Rick Viscomi of the Google CrUX team has published a Google Sheets monitor that tells the CrUX API for a batch of URLs or origins and logs data over time. To use it, create your own copy, open Tools → Script editor, add a script property named CRUX_API_KEY with your API key, and run the script. You can then schedule it to run regularly.

This kind of direct access helps bridge some of the reporting gaps. In one documented case, this monitor confirmed that many URLs in a slow-updating Search Console report had no CrUX data at all, while most of the URLs that did have data had passed. That suggests Search Console's report lags even behind the underlying CrUX data, likely because its proxy values cannot update without fresh field data.

That makes Search Console a reasonable starting point for an overview, but not a great tool for iterating on specific page-level issues. For deeper analysis, monthly CrUX tables are available in BigQuery—though only at origin level. Rick has also documented how to build a CrUX dashboard on top of that data to track overall performance month over month.

LCP dashboard with key metrics at the top, and the percentage of Good, Needs Improvement and Poor for each month over the last 10 months.
CrUX LCP dashboard (Large preview)

What CrUX Doesn’t Tell You

CrUX is the backbone of Google’s Core Web Vitals reporting, but it has blind spots that are easy to overlook when you are staring at a dashboard. The most significant limitation is that CrUX is Chrome-only. Users on Safari, Firefox, Edge, iOS browsers, or legacy browsers such as Internet Explorer are invisible to Google’s field data. Since Chrome dominates the market, the issues surfaced in CrUX will usually affect other browsers too, but there are sites where that assumption fails, and Google’s search monopoly now effectively encourages optimization for its own browser.

Even among Chrome users, CrUX only captures a specific subset. The official definition is:

“[CrUX is] aggregated from users who have opted-in to syncing their browsing history, have not set up a Sync passphrase, and have usage statistic reporting enabled.” — Chrome User Experience Report, Google Developers

Sites with heavy corporate traffic, where IT policies disable these settings, but only for the better-reported public pages if the origin data is being analyzed.

Two more version-related complications can distort CrUX comparisons. The metrics themselves have evolved as Chrome bugs are found and fixed, with CLS seeing continual improvements and a major redefinition shipping in Chrome 91. Field data takes time to reflect those browser changes. Meanwhile, CrUX measures page views, meaning popular pages dominate origin scores, and campaigns that generate high traffic can skew results — making it harder to see recent improvements if visit volumes have since dropped.

Search Console Discrepancies

The Core Web Vitals report in Search Console is based on CrUX but it is not the same dataset. It generally shows only indexed URLs, whereas the raw CrUX data and PageSpeed Insights origin scores include noindexed and logged-in pages. More confusingly, the grouping of sample URLs in that report can be out of sync with actual CrUX data. This happens often enough to be a known frustration.

Since CrUX splits data by form factor — Mobile, Desktop, and Tablet — most tools only expose the first two. The CrUX API and BigQuery can also return Tablet or PHONE data, but it is usually wise to focus on Mobile and Desktop. Either way, these are field measurements: popular pages, noindexed content, and Chrome version distributions are all part of the mix.

None of these quirks are easily handled when the task is simply “fix our Core Web Vitals.” But understanding how the data is gathered and smoothed makes the output far more interpretable, allowing more time to be spent on actual fixes and less on wondering why the numbers are not moving as expected.

Faster Alternatives to CrUX

Waiting 21–28 days for CrUX to reflect a fix is too slow for iterative work. The solution is to look beyond CrUX to replicate its metrics with faster feedback cycles. Several commercial RUM products are good at this; the Web Vitals metrics are exposed as browser APIs in Chromium-based browsers, so they can be gathered directly with the same caveats as CrUX.

For a lighter path, Google’s Web Vitals JavaScript library sends metrics back to Google Analytics:

<script type="module">
  import {getFCP, getLCP, getCLS, getTTFB, getFID} from 'https://unpkg.com/web-vitals?module';

  function sendWebVitals() {
    function sendWebVitalsGAEvents({name, delta, id, entries}) {
      if ("function" == typeof ga) {  
        ga('send', 'event', {
          eventCategory: 'Web Vitals',
          eventAction: name,
          // The `id` value will be unique to the current page load. When sending
          // multiple values from the same page (e.g. for CLS), Google Analytics can
          // compute a total by grouping on this ID (note: requires `eventLabel` to
          // be a dimension in your report).
          eventLabel: id,
          // Google Analytics metrics must be integers, so the value is rounded.
          // For CLS the value is first multiplied by 1000 for greater precision
          // (note: increase the multiplier for greater precision if needed).
          eventValue: Math.round(name === 'CLS' ? delta * 1000 : delta),
          // Use a non-interaction event to avoid affecting bounce rate.
          nonInteraction: true,
          // Use `sendBeacon()` if the browser supports it.
          transport: 'beacon'
        });
      }
    }

    // Register function to send Core Web Vitals and other metrics as they become available
    getFCP(sendWebVitalsGAEvents);
    getLCP(sendWebVitalsGAEvents);
    getCLS(sendWebVitalsGAEvents);
    getTTFB(sendWebVitalsGAEvents);
    getFID(sendWebVitalsGAEvents);

  }

  sendWebVitals();
</script>

The library can be loaded as an external script instead:

<script type="module" src="https://www.smashingmagazine.com/javascript/send-web-vitals.js"></script>

This does add JavaScript to pages that may already be slow because of JavaScript.

Why Field Data Changes the Conversation

The Core Web Vitals matter less as abstract numbers and more as a window into real user experiences. What makes the current push particularly valuable is how it has put Chrome User Experience Report (CrUX) data into the hands of sites that previously never measured real-user performance. CrUX surfaces what visitors actually encounter across their varied devices, connections, and contexts — something lab testing cannot replicate.

For years, the industry leaned on lab data because field data felt unwieldy. Real-user metrics are inherently noisy: network conditions fluctuate, devices age, and user behavior varies. CrUX attempts to smooth that noise into a stable signal, but that same smoothing creates blind spots. Recent changes in performance are slow to appear in the aggregated view, making it harder to validate an optimization quickly.

Working Within the Limits

Knowing where each data source falls short helps you choose the right tool for the question at hand. CrUX gives you confidence about overall trends but obscures short-term shifts. Lab tools give you controlled, repeatable measurements but cannot capture the diversity of real-world browsing. The gap between them is where most misinterpretation happens.

Rather than treating any single source as the whole truth, accept the constraints of each and combine them deliberately. Use CrUX to spot persistent problems, use lab tests to isolate their causes, and then rely on the same field pipeline to confirm whether a fix moved the needle — while remembering that the confirmation will lag behind the deployment.

The motivation behind the Core Web Vitals is clear: performance should be a competitive factor, and the search ranking incentive has drawn attention that purely technical arguments never managed to generate. But the real win is not just better scores; it is that more teams now have a reason to understand what their users experience firsthand.

Approaching Optimization With Realistic Expectations

Understand that no metric is perfect. The trick is to read the data with its limitations in mind and to communicate those limitations across your team. When a graph dips or stalls, know whether you are looking at a genuine regression or simply the shape of the reporting window. When a field measurement disagrees with the lab, know which one reflects the actual user and which one reflects a controlled assumption.

The practical takeaway is to build a workflow that acknowledges the noise:

  • Treat CrUX as a long-term health indicator, not a day-to-day debugging tool.
  • Use lab-based profiling to find why a page is slow in ways field data cannot show.
  • Validate experiments with the same field-based measurement that matters to your business metrics.
  • Learn to reconcile lag time and percentile-based summaries with your own urgency to ship improvements.

The goal is not to chase a perfect score but to build a sustainable practice: measure in the field, diagnose in the lab, and ship with the understanding that the data will catch up.