The fastest way to fool yourself about performance is to run Lighthouse once on a fast laptop over a fast connection, see a green score, and call it done. Core Web Vitals are field metrics — Google measures them on your actual users, on the mid-range Android phones and spotty connections they actually have, and aggregates the result over a rolling 28-day window. That field data is the ranking signal and the proxy for real experience. Your laptop on office wifi is the best case your users will ever see; the field data is the truth. Lab tools are a fast feedback loop, useful for catching a regression before it ships, but they are a sanity check, not the target.
The three metrics, and what each one is really telling you
LCP, INP, and CLS measure three different failures. LCP — largest contentful paint, target under 2.5 seconds — tells you how long the user stares at a half-loaded page before the main content arrives. INP — interaction to next paint, target under 200 milliseconds — replaced FID and measures whether the page actually responds when someone taps or clicks, across the whole session, not just the first input. CLS — cumulative layout shift, target under 0.1 — measures how much the page jumps around as it loads. Each has its own usual suspects, and treating them as one number is how fixes get aimed at the wrong place.
INP is where modern sites actually fail
Since INP replaced FID, a lot of sites that used to pass quietly started failing, because INP is much harder to fake. FID only measured the delay on the first interaction; INP measures responsiveness across the entire session, so a page that felt fine on its first tap but stutters every time the user filters a collection now gets caught. It catches the cost of heavy JavaScript: long tasks that block the main thread, oversized hydration, event handlers doing too much synchronous work, and frameworks shipping more interactivity than the page needs. The fixes are real engineering — shipping less JavaScript, breaking long tasks into smaller chunks, deferring non-critical work to idle time, and being honest about how much of the page actually needs to be interactive at all. There is no caching header that fixes a 600-millisecond INP. You fix it by doing less work on the main thread.
Third-party scripts are the usual culprit
On most sites we audit, the single biggest lever is third-party JavaScript that nobody is accountable for. Tag managers loading a dozen tags, a chat widget pulling 300KB on every page, analytics and A/B testing and a heatmap tool all competing for the main thread. The discipline is to inventory every third-party script, attach an owner and a justification to each, and put the survivors on a leash:
- Inventory every third-party request and the business reason it exists.
- Defer or async anything that is not needed for the first paint.
- Lazy-load chat, heatmap, and review widgets until interaction or idle time.
- Audit tag managers — they are where unowned scripts accumulate fastest.
- Self-host critical fonts and scripts where the third party is just a CDN.
CLS is small, fixable, and embarrassing to ignore
Cumulative layout shift is the most fixable of the three and the one teams let slide the longest. It is the page jumping under your thumb — an image loading without reserved space and shoving the text down, a font swap reflowing a paragraph, a cookie banner or promo bar injecting itself after first paint, an ad slot expanding once it fills. Every one of those has a known fix: set explicit dimensions on media and embeds, reserve space for anything injected late, and load fonts so the swap does not reflow the layout. Unlike INP, CLS rarely requires architectural change. It mostly requires caring, which is why a high CLS score reads as neglect more than as a hard engineering problem.
Image strategy: the cheapest LCP win
The LCP element is almost always an image — usually the hero — which means image strategy is the cheapest large win available on most sites. Serve modern formats like WebP or AVIF, size images to their actual rendered dimensions instead of shipping a 4000px original into a 600px slot, set explicit width and height attributes so the browser reserves the space and the page does not jump when the image arrives, and preload the hero so the browser starts fetching it before it finishes parsing the rest of the document. Done properly, image work alone moves both LCP and CLS at once, and it rarely requires touching application logic — which is why it is the first place we look and often the highest return on the least risk.
Synthetic scores are a sanity check. The number that pays rent is the one Google measured on your users last month.— How we scope every performance engagement
We tune to the CrUX dataset and Search Console field data, treat Lighthouse as the fast feedback loop, and start every engagement with a written report that names the top three to five levers and what each one should move. That is the shape of our performance optimization work — quick wins in the first sprint, structural work after, and monitoring so the field data does not quietly regress six months later.