Before you can fix performance you have to measure core web vitals correctly, and this is where most sites go wrong before writing a line of code. There are two entirely different measurement systems, they routinely disagree by wide margins, and only one of them feeds Google’s page experience signal. Confusing them wastes months.
Field data comes from real visitors. Lab data comes from a simulated load in a controlled environment. Both are useful. They answer different questions and are never interchangeable.
The Three Metrics and What Counts as Passing
You are measuring three things, each against a threshold at the 75th percentile of field measurements over a trailing 28 days:
- LCP — Largest Contentful Paint, good at 2.5 seconds or less
- INP — Interaction to Next Paint, good at 200 milliseconds or less
- CLS — Cumulative Layout Shift, good at 0.1 or less
A URL passes only when all three are in the good range. The 75th percentile is doing important work here: it means the slowest quarter of your visits can exceed the threshold and you still pass, but it also means your average visitor’s experience is not what is being measured. Reporting a median LCP to your team is reporting the wrong number.
If your dashboard still shows First Input Delay, it is out of date. FID was replaced by INP in March 2024 and is no longer collected as a Core Web Vital.
Field Data: CrUX and Where to Get It
The Chrome User Experience Report aggregates measurements from real Chrome users who have opted into reporting. This is the dataset Google uses. Four ways to read it:
- Search Console’s Core Web Vitals report — property-wide, grouped by similar URLs, split by mobile and desktop. Best for triage and trend.
- PageSpeed Insights — per-URL field data at the top of the report, with origin-level data underneath. Best for a specific page.
- The CrUX API — programmatic access to the same 28-day aggregate for a URL or origin. Best for building your own monitoring.
- The CrUX BigQuery dataset — monthly historical data, useful for long-range analysis and competitor benchmarking.
One hard limitation: CrUX needs a minimum volume of samples. Low-traffic URLs have no field data at all, and PageSpeed Insights will fall back to origin-level numbers for the whole site. On a small site, many individual pages will never have their own field data — which does not mean they are fine, only that they are unmeasured.
Lab Data: Lighthouse and Its Blind Spots
Lighthouse loads your page once, on a simulated mid-tier mobile device over a throttled connection, and reports what happened. It is reproducible, it runs before deploy, and it produces a specific diagnostic list. That makes it excellent for debugging.
It also has structural blind spots. Lighthouse cannot measure INP at all, because INP requires actual user interactions — the lab substitute is Total Blocking Time, which correlates loosely and is not the same metric. Lab CLS misses shifts triggered by scrolling or interaction, since the simulated visit does neither. And lab runs vary between executions on the same machine, so a five-point score change usually means nothing.
Treat the Lighthouse performance score as a diagnostic summary, not a target. It is a weighted composite that includes metrics which are not Core Web Vitals at all.
Real User Monitoring: Measuring Your Own Traffic
CrUX only includes Chrome users who opted in, which excludes Safari and Firefox entirely and lags by weeks. If you want to see the effect of a deploy within hours, you need your own RUM.
Google’s web-vitals JavaScript library is the standard way to collect this. It reports each metric using the same definitions CrUX uses, and you send the values to your own endpoint or analytics tool:
import {onLCP, onINP, onCLS} from 'web-vitals';
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
Two things to get right when you store it. Record the raw values, not averages, so you can compute percentiles later — an average LCP hides exactly the tail the metric is designed to expose. And segment by device type, connection, country, and template. A site-wide number tells you nothing actionable; “mobile product pages in Southeast Asia are at 4.1 seconds” tells you where to start.
Reading the Difference Between Lab and Field
When lab and field disagree, the gap is information rather than an error. A few common patterns and what they mean:
- Lab good, field bad — your users are on slower devices or networks than the simulation assumes, or a third-party script only fires for real sessions
- Lab bad, field good — your caching, CDN, or repeat-visitor profile is doing heavy lifting the cold lab run never sees
- Field INP bad, lab TBT fine — the problem is in interaction handlers rather than initial load, which lab tooling barely touches
Always let field data decide priority. Lab data then explains the mechanism.
Measuring Competitors and Setting a Target
CrUX is public at the origin level, which means you can pull field data for any site with enough traffic — including every competitor on page one. Run their domains through PageSpeed Insights or query the CrUX API directly and you have an honest performance benchmark rather than an abstract threshold.
Benchmark against the weakest page-one competitor, not the fastest. If the slowest result ranking for your target query has a 3.4-second LCP and you are at 4.1, you know exactly how much ground you need and can stop there rather than chasing a number nobody in your SERP achieves.
Two caveats. Origin-level data averages the whole site, so a competitor’s fast marketing pages can mask slow product pages. And performance is only one input among many — a competitor passing all three metrics while you fail is a reason to fix yours, not an explanation for the entire ranking gap.
Setting a Measurement Cadence
Field data updates on a 28-day trailing window, so a fix shipped today shows up gradually over the next month rather than immediately. Check Search Console weekly for trend, not daily for movement. Your own RUM is the fast feedback loop — a bad deploy shows up within hours if you segment by release.
Set an alert threshold rather than reading dashboards. A weekly job that queries the CrUX API for your top twenty templates and posts a message when any metric crosses from good to needs-improvement will catch more regressions than a dashboard nobody opens. Alerts on change, not on state.
Run Lighthouse in CI on a fixed set of representative templates rather than on every URL. Home, category, product or article, and one heavy interactive page usually covers it. Fail the build on large regressions, not small ones, or you will be chasing run-to-run noise.
Putting It All in One View
The practical difficulty is that these sources live in four different tools with four different update schedules, and nothing joins them to the pages that actually earn traffic. That is where most measurement programs quietly die.
SEO Rocket reports PageSpeed and Core Web Vitals with real-user field data shown beside the lab metrics, so the “which number do I trust” question is answered on the same screen. Alongside full-site crawls that give concrete evidence per issue — actual URLs, titles, and H1 text — it lets you sort performance problems by the pages that matter rather than by whichever URL you happened to test. Measure first, then fix. The order saves more time than any single optimization.