Understanding Core Web Vitals (and How to Improve Them)
Core Web Vitals affect both user experience and search ranking. Here's what LCP, INP, and CLS actually measure and the highest-impact ways to fix each one.
Core Web Vitals are three metrics Google uses to score how a page feels to real users: Largest Contentful Paint (loading — good is 2.5 seconds or less), Interaction to Next Paint (responsiveness — 200 milliseconds or less), and Cumulative Layout Shift (visual stability — 0.1 or less). They feed into search ranking, but their real value is simpler: they’re a measurable proxy for whether visitors stick around. Google’s reference for the program lives at web.dev/articles/vitals.
One detail explains most confusion about scores, so internalize it first: each metric is judged at the 75th percentile of real visits. Your page passes only if three-quarters of visits hit the target — a fast experience on your laptop proves nothing about the phones your audience actually uses.
LCP: how fast the main thing shows up
Largest Contentful Paint measures the time from navigation until the largest visible element — usually the hero image or headline — finishes rendering. It’s the metric closest to a user’s gut sense of “the page has loaded.”
Highest-impact fixes, roughly in order:
- Speed up the server response. Nothing renders before the first byte arrives. Cache HTML where you can — any caching layer between the user and your origin cuts time to first byte — and serve assets from a CDN so responses come from near the visitor.
- Prioritize the LCP image. Put it in the initial HTML as a plain
<img>— not a CSS background or a client-side render — addfetchpriority="high", and preload it if it’s discovered late:
<link rel="preload" as="image" href="/hero.avif" fetchpriority="high">
- Never lazy-load the LCP element.
loading="lazy"on the hero image is a classic self-inflicted wound. - Cut render-blocking CSS and JavaScript, and serve modern formats (AVIF/WebP) at the size actually displayed.
INP: how fast the page reacts
Interaction to Next Paint measures the delay between a user interaction — click, tap, key press — and the next visual update. It replaced First Input Delay in 2024 and is stricter: it considers interactions across the whole visit and reports one of the worst, so a single janky menu can fail the page.
INP is almost always a JavaScript problem. The main thread does one thing at a time, so a long task means the paint after your click has to wait.
- Break up long tasks. Anything over 50ms of continuous work delays interactions; chunk it and yield back to the browser between pieces.
- Ship less JavaScript. Framework-heavy pages pay for hydration — re-running component code in the browser before anything responds. Server-render more, hydrate less, and let a bundler like Vite split code by route so users only download what the page needs.
- Avoid re-render storms. A keystroke that re-renders an entire component tree turns typing into lag. Batch state updates and keep per-interaction work proportional to what actually changed.
- Move non-urgent work out of handlers. Analytics, logging, and prefetching don’t belong in the click path.
Interactivity doesn’t have to mean heavy scripts — static site search with Pagefind is a good example of adding a rich feature while keeping the main thread quiet.
CLS: does the page hold still
Cumulative Layout Shift measures unexpected movement — content jumping as things load. The formal score multiplies how much of the viewport shifted by how far it moved, but the intuition is enough: this is the tapped-the-wrong-button-because-an-ad-appeared metric.
- Give images and embeds dimensions.
widthandheightattributes (or CSSaspect-ratio) let the browser reserve space before the file arrives. - Reserve space for ads and iframes. Fixed-size slots with a
min-heightare the single biggest fix on monetized sites — an ad that pops in and shoves the article down is the canonical CLS failure. - Handle web fonts. A late font that reflows the page counts too. Preload critical fonts and pair
font-display: swapwith a fallback font that’s metrically close. - Insert new content below the fold or into space you reserved — never push existing content down.
Field data vs. lab data (and why they disagree)
There are two kinds of measurement, and mixing them up wastes debugging time:
| Field data (CrUX) | Lab data (Lighthouse) | |
|---|---|---|
| Source | Real Chrome users, 28-day rolling window | One synthetic load on demand |
| Conditions | Every device and network your visitors have | One simulated device and connection |
| Includes INP | Yes — real interactions | No — lab runs don’t interact |
| Used for ranking | Yes | No |
| Best for | Knowing whether you actually pass | Reproducing and fixing problems |
A page can ace Lighthouse and still fail Core Web Vitals in the field, because the lab simulates one mid-range profile while your field data includes slow phones on cellular connections. The reverse happens too. Treat field data as the scoreboard and lab data as the debugger.
How to measure yours
PageSpeed Insights is the fastest start: it shows CrUX field data for your URL — when Google has enough traffic to report it — alongside a fresh Lighthouse run with diagnostics. For site-wide coverage, Search Console’s Core Web Vitals report groups similar URLs, which is how you spot patterns: every product page failing CLS points at a template, not one page.
Fix whichever metric sits furthest from its threshold, ship, then wait. Field data is a 28-day window, so improvements take weeks to register fully.
Do Core Web Vitals affect rankings?
Yes — but keep it in proportion. Page experience is a ranking consideration and vitals are how it’s measured, yet content relevance dominates. A thin page will not outrank a genuinely useful one because it loads 400ms faster. The realistic framing: bad vitals can drag you down in competitive results, good vitals remove that drag, and users abandon slow pages regardless of what Google thinks. Optimize for the visitor; the ranking benefit comes along for free.
The takeaway
Core Web Vitals reduce “does this page feel good” to three numbers: LCP ≤ 2.5s, INP ≤ 200ms, CLS ≤ 0.1, each judged at the 75th percentile of real visits. Prioritize the hero image and server response for LCP, ship less JavaScript in shorter tasks for INP, and reserve space for everything that loads late for CLS. Debug in the lab, but judge yourself on field data — that’s what users experience and what ranking looks at. And remember the ceiling: speed helps, but nothing rescues content people don’t want.
Tagged
Keep reading
Takina · · 4 min read What Is the Beacon API? navigator.sendBeacon()
The Beacon API lets a page send one last async request as it unloads, without blocking navigation or racing the browser's page teardown.
Takina · · 3 min read What Is Fetch Priority? The fetchpriority Attribute
fetchpriority lets you tell the browser which resources matter most, overriding its default heuristics to load critical assets sooner.
Takina · · 4 min read requestIdleCallback Explained
requestIdleCallback runs low-priority JavaScript when the browser is idle, without blocking rendering, input, or the main thread.