Summary
Core Web Vitals are three field-measurable metrics that quantify real user experience: LCP tracks loading, INP tracks responsiveness (replacing FID in March 2024), and CLS tracks layout stability. Good thresholds are LCP ≤2.5 s, INP ≤200 ms, CLS ≤0.1. They drive Google Search ranking and are the sharpest signal for user-facing performance regressions.
Jump to the interview angleThe three Core Web Vitals at a glance
| Metric | What it measures | Good threshold | Top cause of failure | |
|---|---|---|---|---|
| LCP | Time to render largest above-fold image or text block | ≤ 2.5 s | Slow TTFB, render-blocking CSS, unpreloaded hero image | |
| INP | 98th-percentile input-to-next-paint delay across all interactions | ≤ 200 ms | Long JS tasks blocking main thread between input and frame | |
| CLS | Sum of impact × distance for unexpected layout shifts | ≤ 0.1 | Images or iframes without explicit dimensions, late-injected DOM |
Lab vs field data
Lighthouse (lab) runs a single cold load in a throttled environment — good for catching regressions in CI. CrUX (field) reports 28-day rolling percentiles from real Chrome users and is what Google uses for Search ranking. A score that looks fine in Lighthouse can still fail in the field if ads, late fonts, or real interactions spike the metrics.
Measure all three vitals with web-vitals v4
Install web-vitals (npm package by Google). Each on* function fires when the metric value is ready and again on updates. Pass reportAllChanges: true so INP updates as the user interacts rather than only on page unload.
import { onLCP, onINP, onCLS } from "web-vitals";
import type { Metric } from "web-vitals";
function send(metric: Metric): void {
// Replace with your RUM endpoint or analytics call.
navigator.sendBeacon("/vitals", JSON.stringify({
name: metric.name, // "LCP" | "INP" | "CLS"
value: metric.value, // ms for LCP/INP, unitless for CLS
rating: metric.rating, // "good" | "needs-improvement" | "poor"
id: metric.id,
delta: metric.delta,
}));
}
onLCP(send);
onINP(send, { reportAllChanges: true });
onCLS(send, { reportAllChanges: true });rating maps the raw value against good/poor thresholds automatically — alert on regressions without hardcoding numbers.
Trade-offs of the CWV framework
Pros
- Ties user perception to measurable numbers, not vague 'feels fast' reports.
- CrUX field data gives a 28-day real-device baseline no synthetic tool can match.
- INP catches slow interactions that FID missed — full input-to-paint delay.
- Three metrics cover load, interactivity, and stability — orthogonal failure modes.
Cons
- CrUX requires enough real-user traffic; low-traffic pages get no field data.
- Lab tools can't reproduce session-level INP across many interactions.
- CLS is easily gamed by deferring all layout shifts to after user input.
- LCP origin attribution is hard: hero image, TTFB, render-blocking CSS, or all three.
Interview angle
Expect questions on what each metric measures, why INP replaced FID, and how to diagnose regressions in production.
Soundbite: "FID only measured input delay; INP measures the full interaction-to-paint delay at the 98th percentile — it catches slow event handlers that FID missed."
Key terms
- LCP
- Time to render the largest above-the-fold image or text block; good ≤2.5 s.
- INP
- 98th-percentile input-to-paint delay across all interactions; good ≤200 ms.
- CLS
- Sum of impact × distance shift scores for unexpected layout shifts; good ≤0.1.
- CrUX
- Chrome UX Report — 28-day rolling field data from real Chrome users, used for ranking.
- LoAF
- Long Animation Frame — browser entry identifying frames that exceed 50 ms.