LCP under 2.5s
Almost always image-bound. Preload the hero image, serve it in AVIF or WebP, set explicit width/height, and host it on a CDN with HTTP/3. Defer everything that isn't above-the-fold.
INP under 200ms
INP replaced FID in March 2024. The fix is the same as for long tasks: break up JavaScript work, debounce input handlers, and move heavy logic off the main thread with Web Workers where possible.
CLS under 0.1
Reserve space for every image, embed, and ad. Avoid injecting content above existing content. Use font-display: optional or matched fallback font metrics to prevent FOIT/FOUT shift.
Measure in the field
Lab tools (Lighthouse) lie. Use Chrome UX Report (CrUX) data and a RUM tool like web-vitals.js to capture real visitor metrics segmented by device and country.
The thresholds, in one place
Every metric is judged at the 75th percentile of real visits, split between mobile and desktop. LCP: good under 2.5s, needs improvement 2.5-4.0s, poor above 4.0s. INP: good under 200ms, needs improvement 200-500ms, poor above 500ms. CLS: good under 0.10, needs improvement 0.10-0.25, poor above 0.25. A URL group passes only when all three are in the good band, so the metric closest to its boundary is the one worth fixing first - not the one with the worst-looking chart.
A repeatable diagnosis workflow
1. Open the Core Web Vitals report in Search Console and note which URL group fails and on which device. 2. Take one representative URL and confirm the failure in CrUX rather than Lighthouse. 3. Reproduce it in DevTools with mobile CPU throttled 4x and a Slow 4G profile. 4. For LCP, read the LCP element in the Performance panel and classify the time as TTFB, resource load delay, load time, or render delay - each has a different fix. 5. For INP, record an interaction and look for the long task blocking it. 6. Ship one change at a time and keep a RUM measurement running so you can attribute the improvement.
Worked example: a 4.1s LCP template
A content template failed LCP at 4.1s on mobile. The breakdown was 0.5s TTFB, 1.9s resource load delay, 1.4s load time, 0.3s render delay. The hero was lazy-loaded and discovered only after the CSS parsed, and it was a 1.4MB PNG. Three changes - removing lazy-loading on the hero, adding a preload with fetchpriority=high, and serving a correctly sized AVIF - cut load delay to 0.2s and load time to 0.4s, landing LCP at 1.4s. No framework change and no CDN change was needed; the metric was dominated by discovery, not bandwidth.
Common regressions to watch for
Third-party tags added by marketing are the most frequent INP regression, and consent banners injected above content are the most frequent CLS regression. Guard against both: load tags with async or via a worker-based tag manager, reserve the banner's height, and add a budget check to your deploy process so a regression is caught before it enters the 28-day field window.
A performance budget you can enforce in CI
Thresholds only hold if a build can fail. A budget that works in practice: hero image under 120KB after encoding, total render-blocking CSS under 40KB, total first-party JavaScript under 170KB compressed, zero elements above the fold without explicit dimensions, and no third-party script on the critical path. Wire it to a Lighthouse CI run on one representative URL per template - not every URL - and treat the run as a regression gate rather than a score to optimize. Lab numbers are unreliable as absolute values but very reliable as change detectors between two commits of the same template.
Read the metrics per template, not per site
Site-wide Core Web Vitals averages hide the failure. Group URLs the way your codebase does - home, article, category, product, search results - and pull field data for each group separately. In almost every audit we run, one template accounts for most of the failing URLs, and its fix is a single change applied once. Chasing a site-level score instead produces scattered work with no measurable movement in the 75th percentile.