This isn’t a contradiction to resolve, it’s two different measurements of two different things, and both can be simultaneously correct. Lighthouse is a single synthetic run under fixed, typically favorable conditions: a specific simulated network/CPU throttling profile, no real device diversity, no real network variability, and no logged-in or personalized states. CrUX aggregates real Chrome users across every device tier, network condition, and geographic location that actually visits your site, and its 75th-percentile figure specifically captures the realistic tail, the slower quarter of real visits, that a single lab run structurally cannot see. The diagnostic move isn’t to figure out which one is “wrong,” it’s to figure out what real-world condition Lighthouse’s lab environment doesn’t represent for your actual traffic.
Why lab conditions miss real-world LCP failures
Google’s own documentation on lab versus field data is direct about this: they are complementary, not redundant, measurements. Lab data (Lighthouse, PageSpeed Insights’ lab section) is reproducible and useful for debugging because it holds conditions constant, but “constant” means it’s simulating one specific scenario, not the full distribution of real usage. Field data (CrUX) is the aggregate of actual page loads by real Chrome users, with all their variance in device CPU power, network quality, cache state, and behavior.
A perfect Lighthouse score paired with a failing p75 field LCP typically points to one or more of the following gaps between the lab condition and your real traffic mix:
Device performance variance. Lighthouse simulates a mid-tier mobile CPU profile under specific throttling. If a meaningful share of your real traffic comes from lower-end devices with significantly less CPU/GPU headroom, LCP-affecting work (image decode, JS execution blocking render, web font processing) takes measurably longer on those real devices than in the simulated profile.
Network condition variance. Lighthouse throttles to a fixed network profile. Real users on slower mobile connections, congested networks, or in regions with worse peering/CDN coverage experience genuinely slower resource delivery than the lab’s fixed simulation, which directly inflates real LCP without touching the lab score at all.
Cache state. A single Lighthouse run is typically a cold load. Real user sessions include a mix of cold and warm cache states, but they also include first-time visitors on a cold CDN edge cache, or resources that expired and need refetching, states a controlled lab run doesn’t necessarily replicate representatively.
Personalization and real content variability. Logged-in states, A/B test variants, personalized above-the-fold content, or dynamically injected ads/third-party content can all make the actual LCP element or its loading path different from what a generic Lighthouse crawl of the page tests.
Origin-level versus URL-level CrUX aggregation. A common misdiagnosis is comparing a Lighthouse run on one specific URL against a CrUX figure that’s actually aggregated at the origin level rather than the URL level. If Search Console or the CrUX API is reporting origin-level data because the specific URL doesn’t have enough traffic for its own URL-level bucket, the p75 failure you’re looking at may be dominated by template patterns or content on other pages of the site entirely, not the page you’re testing in Lighthouse. Always check whether the CrUX figure you’re comparing against is URL-level or origin-level before concluding the specific page you ran Lighthouse on is the actual source of the failure.
Diagnosing a Lighthouse-versus-CrUX LCP gap
Segment the CrUX data (via the CrUX API, BigQuery, or Search Console’s Core Web Vitals report) by device type and connection where possible, to identify which segment of real users is actually failing, rather than treating “failing at p75” as a single undifferentiated problem.
Use PageSpeed Insights on the exact URL rather than only running local Lighthouse, since PageSpeed Insights surfaces both lab and available field CrUX data side by side for that URL, making the gap visible directly rather than inferred.
If available, deploy a RUM solution (such as the web-vitals JavaScript library with its attribution build) to capture real LCP element and timing breakdowns from actual users, which will show you concretely which device/network segments and which LCP element variants are driving the p75 failure, information no lab tool can give you since it isn’t sampling your real population.
Run WebPageTest against the URL with a device/connection profile that approximates your slowest meaningful traffic segment (identified from the CrUX device-type breakdown), rather than relying only on Lighthouse’s default mid-tier simulation. WebPageTest lets you pick specific real device and connection presets, and its filmstrip and waterfall views can reveal whether the LCP element itself changes identity between a fast and a throttled run (for example, a hero image winning LCP on a fast connection but a fallback text block or a slower-loading web-font-rendered heading becoming the LCP candidate on a throttled one). If the LCP element isn’t even the same node across conditions, the fix target changes entirely.
Also check whether fetchpriority="high" or a <link rel="preload"> hint exists for the actual LCP resource, and whether it’s being applied consistently regardless of device or connection. A missing or inconsistently applied priority hint is invisible in a single fast lab run (the resource loads quickly enough regardless) but becomes a meaningful real-world delay once contended bandwidth or a slower CPU pushes resource discovery later in the load sequence.
Account for the timing lag built into CrUX before assuming the failure reflects the page as it currently exists. CrUX reports a rolling 28-day window, so if you shipped a genuine performance fix recently, the field data you’re looking at may still be dominated by pre-fix sessions and hasn’t caught up yet. In that situation a perfect current Lighthouse score and a failing CrUX figure aren’t describing a real ongoing gap at all, they’re describing the same page at two different points in time. Note the deployment date of any relevant change and compare it against the CrUX data’s collection period (visible in the CrUX API response or BigQuery table date) before concluding the lab-versus-field gap is still live.
Treat the lab score as confirmation that the page is not fundamentally broken (no obvious lab-visible regression), and treat the field data as the metric that actually determines Core Web Vitals pass/fail status for ranking purposes, since Google’s page-experience signal is built from field data, not lab scores.