The Web Performance Metrics That Actually Matter (Lighthouse Isn't One of Them)
I spent the better part of a quarter a few years back chasing a 100 on Lighthouse for a marketing site. We got there. Green across the board — performance, accessibility, best practices, SEO. I remember screenshotting it and posting it in Slack like we'd won something. Three weeks later, our product analytics showed bounce rate on that same page hadn't moved a single percentage point. That was the moment I stopped trusting lab scores as a proxy for anything real, and it fundamentally changed how I think about performance work.
The problem isn't that Lighthouse is wrong. It's that Lighthouse measures a single page load, on a single simulated device, on a single simulated network, from a data center that has nothing to do with where your users actually are. It's a lab test. It's useful the way a dyno test is useful for a car engine — it tells you something about the machine in isolation, but it tells you nothing about how the car performs on the actual road your customers drive on, in actual traffic, with actual potholes.
Lab data versus field data, and why the gap is the whole story
Lab data is synthetic and reproducible. You run it in CI, you get the same number every time (roughly), and you can gate deploys on it. Field data — often called Real User Monitoring, or RUM — is what happens when actual humans with actual devices on actual networks load your actual pages. The gap between the two is usually where the truth lives.
I've seen sites with a 95+ Lighthouse performance score and a genuinely bad field LCP because the lab run doesn't account for a third-party chat widget that only loads for logged-in users, or an A/B testing script that blocks render for returning visitors, or the fact that 40% of your traffic is on mid-range Android phones in markets with throttled mobile networks. Lighthouse, by default, simulates a fairly generic mobile profile. Your real traffic distribution is never that clean.
This is why Google's Core Web Vitals program leans so heavily on CrUX (the Chrome User Experience Report) for actual ranking signals, not synthetic Lighthouse runs. If you're optimizing for search rankings or, more importantly, for actual user happiness, you need to be looking at field percentiles, not lab averages.
The three metrics, explained the way I wish someone had explained them to me
LCP (Largest Contentful Paint) measures when the largest visible element — usually a hero image, a big block of text, or a video poster — finishes rendering. It's a proxy for "does this page feel loaded." The threshold Google uses is 2.5 seconds at the 75th percentile for "good." I used to think LCP was purely a network/server problem, but in practice I've fixed more LCP regressions by finding render-blocking CSS and JS than by touching the CDN. A classic offender: a for a font that isn't actually needed for the LCP element, competing for bandwidth with the image that is.
INP (Interaction to Next Paint) replaced First Input Delay in March 2024, and it's the one most teams still don't have proper instrumentation for. INP measures the latency of the worst (well, roughly the 98th percentile) interaction across the entire page lifecycle — not just the first click, but every click, tap, and keypress. This is the metric that catches the sluggish dropdown, the janky modal, the search box that doesn't respond until three re-renders finish. If you've got a React app with a poorly memoized context provider causing cascading re-renders on every keystroke, INP will expose it in a way FID never did.
CLS (Cumulative Layout Shift) measures visual stability — how much stuff jumps around as the page loads. Ads without reserved space, images without explicit width/height, web fonts causing a FOUT/FOIT reflow, a cookie banner that shoves content down after the fact. CLS is usually the easiest of the three to fix and the most embarrassing to leave broken, because users notice it viscerally even if they can't name it.
Instrumenting field data yourself
You don't need a big observability contract to start collecting real user data. The web-vitals library from the Chrome team is the standard starting point:
import { onLCP, onINP, onCLS, onTTFB } from 'web-vitals';
function sendToAnalytics(metric: { name: string; value: number; id: string; rating: string }) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating,
id: metric.id,
page: location.pathname,
});
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/vitals', body);
} else {
fetch('/api/vitals', { body, method: 'POST', keepalive: true });
}
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
onTTFB(sendToAnalytics);
On the backend, you just need somewhere to dump these events and aggregate by percentile, page, device type, and connection type. If you're already paying for Datadog or Sentry, both have RUM products that will do the aggregation for you and let you segment by release, which is genuinely useful when you want to answer "did last Tuesday's deploy regress INP for mobile Safari users." Sentry's Performance monitoring in particular ties nicely into error tracking you probably already have set up, so a slow interaction and a JS exception in the same session show up connected.
If you want zero-dependency field data without a vendor, you can also just query CrUX directly through the BigQuery public dataset or the CrUX API, keyed by origin. It's 28-day rolling aggregates, so it's laggy, but it's genuinely what search ranking uses, and it costs nothing.
curl "https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=$API_KEY" \
-H "Content-Type: application/json" \
-d '{"origin": "https://example.com", "metrics": ["largest_contentful_paint", "interaction_to_next_paint", "cumulative_layout_shift"]}'
Fixing what you find
Once you actually have field data segmented by device and page, the fixes tend to cluster into a few buckets. For LCP, it's almost always render-blocking resources — audit your for synchronous scripts, make sure your LCP image has fetchpriority="high" and isn't lazy-loaded, and check whether your CDN is actually serving from an edge close to your users. For INP, profile with the Chrome DevTools Performance panel, filter for long tasks over 50ms, and look specifically at what's happening on input events — debounce work you don't need synchronously, move heavy computation off the main thread with a Web Worker if you can. For CLS, it's almost mechanical: reserve space for every image, ad slot, and embed with explicit dimensions or aspect-ratio in CSS, and load web fonts with font-display: optional or preload them if brand consistency on first paint really matters that much.
Tying it to the business
The reason I care about this beyond professional pride is that the correlation between Core Web Vitals and business metrics is well documented and, in my experience, real. Vodafone found a substantial improvement in sales after improving LCP. The Financial Times built a model directly tying subscriber engagement to load time. I've personally watched a checkout funnel's conversion rate move after we fixed a CLS issue where the "Place Order" button shifted down 40px right as someone was about to tap it — that wasn't a performance bug, that was a revenue bug that happened to be caused by a layout shift.
The mistake most teams make is treating performance as an engineering purity exercise, chasing a synthetic number because it's green in CI. The teams that actually move the needle treat it as a product metric, instrumented in the field, segmented by the users and pages that matter most to the business, and tied to a dashboard that a product manager actually looks at. Lighthouse still has a place — run it in CI as a regression guardrail so you catch obvious mistakes before they ship — but it should never be the metric you report up. Field data, at the 75th percentile, segmented by page template and device class, is the only performance number I trust enough to put in a quarterly review anymore.
Related Posts
Sponsor Our Newsletter
Reach thousands of developers who are actively evaluating AI tools, MCP servers, and dev infrastructure. Our weekly newsletter goes to engaged technical decision-makers.
All sponsored content is clearly labeled per our editorial policy.