Lighthouse scores diverge from real-world Core Web Vitals because a lab run is a single measurement under fixed, simulated conditions, while real-world performance is an aggregate across enormous variance in device capability, network quality, cache state, and page state. There isn’t a single universal direction of error, some sites see Lighthouse look better than reality, others see it look worse, because the gap depends entirely on how different your actual traffic mix is from Lighthouse’s specific simulated profile.
Why lab and field Core Web Vitals scores diverge
Fixed throttling versus real distribution. Lighthouse applies a specific simulated CPU and network throttling profile intended to approximate a mid-tier mobile device on a constrained connection. If your real user base skews toward higher-end devices and fast connections, Lighthouse will tend to underestimate real performance (real users do better than the simulated profile suggests). If your real base skews toward lower-end devices, older hardware, or genuinely poor network conditions in some regions, Lighthouse will overestimate real performance, since real users are worse off than the simulated profile.
Single run versus aggregated variance. A Lighthouse report is one run (or a small number of runs if you use the median-run mode), while CrUX’s field metrics aggregate real sessions over a rolling 28-day window and report percentile values (typically p75). A single run can’t capture the tail of real-world variance the way an aggregated percentile does, so lab scores structurally miss whatever is happening in the slower tail of real usage.
No real third-party variability. A Lighthouse run typically loads the page in a clean, isolated context. In production, ad auctions, real-time personalization, and third-party scripts behave dynamically and inconsistently across real sessions (different ad creatives, different auction latencies, different consent-management states), introducing main-thread cost and network requests a single clean lab run doesn’t reproduce, which tends to make lab scores look better than production reality for pages with meaningful third-party or ad load.
Cache state mismatches. A single lab run is typically a cold-cache load (or sometimes deliberately warm, depending on configuration), while real traffic includes a genuine mix of first-time cold loads, warm repeat-visit loads, and everything in between across different CDN edge cache states. This can push the comparison in either direction depending on which cache state dominates your real traffic and which one Lighthouse happens to simulate.
Geographic and CDN routing differences. Lighthouse (particularly if run from a fixed location such as PageSpeed Insights’ testing infrastructure) tests from a specific vantage point. Real users hit your CDN from wherever they physically are, and regional CDN coverage gaps or routing inefficiencies for specific geographies won’t show up in a lab test run from a well-served location.
Protocol and connection-reuse differences. A single Lighthouse run establishes a fresh connection to the origin or CDN edge for that one request. Real browsers on repeat visits often reuse warm HTTP/2 or HTTP/3 connections, avoiding the TLS and TCP (or QUIC) handshake overhead that a cold lab run pays every time. Conversely, if your CDN or origin has inconsistent HTTP/3 support across edge locations, some real users get the faster protocol and others fall back to HTTP/2, a split a single lab run from one vantage point simply can’t represent. This can push the comparison either way depending on which connection state dominates your real traffic.
Extension and browser-configuration noise (local Lighthouse specifically). Running Lighthouse locally in Chrome DevTools, rather than through PageSpeed Insights’ server-side infrastructure, introduces additional variance from installed extensions, background processes, and machine load competing for CPU during the trace. This isn’t a factor in real user CrUX data at all, but it can make locally-run Lighthouse scores inconsistent even run-to-run on the same machine, which is a separate problem from the lab-versus-field gap and worth ruling out before attributing a discrepancy to real-world traffic variance.
Page-state and session-history mismatches. Lighthouse loads a URL fresh, as if it were the very first page a visitor ever opened in that browser: no prior navigation history, no back-forward cache, no service worker already installed from an earlier visit on the same site. Real sessions frequently arrive at a page after already having visited another page on the same domain, which means a service worker may already be active and serving cached responses, or the browser’s back-forward cache may restore a previous render almost instantly. Both of those real-world paths can make actual field performance meaningfully better than what a cold, first-visit lab run captures, and neither is something a single Lighthouse pass simulates unless you specifically configure it to test a warmed session.
Using Lighthouse and CrUX correctly together
Don’t treat Lighthouse as a predictor of your field score, treat it as a debugging tool for a specific, reproducible scenario. Use CrUX (via Search Console’s Core Web Vitals report, the CrUX API, or BigQuery) as the authoritative real-world signal, since that’s also what determines actual Core Web Vitals pass/fail status.
When lab and field diverge meaningfully, segment the field data by device category and effective connection type to identify which real-world condition Lighthouse’s fixed profile isn’t representing. That segmentation tells you whether the gap is a device-performance story, a network story, or a third-party/ad-load story, each of which points to a different fix.
Rule out local measurement noise before drawing conclusions about real-world variance: run Lighthouse multiple times (PageSpeed Insights’ server infrastructure or a dedicated Lighthouse CI setup rather than a single ad hoc DevTools run) and check the spread between runs. If successive lab runs on the same URL disagree with each other by a wide margin, part of what looks like a lab-versus-field gap may actually be lab measurement instability, not a genuine reflection of real-world conditions.
Where the third-party or ad-load explanation seems plausible, use Chrome DevTools’ Performance panel or the Request Blocking feature to compare a trace with third-party scripts present against one with them stripped out. If performance recovers substantially with third parties removed, that confirms the gap is attributable to dynamic production-only load (ad auctions, consent management platforms, personalization scripts) rather than to your own first-party code, which changes where remediation effort should go: toward loading strategy and vendor governance rather than your own bundle.
No universal “Lighthouse overestimates by X%” or “underestimates by Y%” figure exists or should be trusted if you see one claimed, since the direction and magnitude of the gap is a function of your specific traffic mix against Lighthouse’s specific fixed simulation profile, not a fixed constant across sites.