Core Web Vitals: A Developer's Guide to LCP, INP and CLS

A practical developer guide to Core Web Vitals — what LCP, INP and CLS measure, good thresholds, how to measure with field and lab data, and concrete fixes for each metric.

By Danyal Ahmed - Data Scientist · · 4 min read

Core Web Vitals are Google's metrics for real-world user experience: how fast the main content loads, how quickly the page responds to interactions, and how stable the layout is. They're part of Google's page experience signals for search, but more importantly, they correlate with what users feel. Slow, janky pages lose visitors and conversions.

Key takeaways

  • The three Core Web Vitals: LCP (loading), INP (responsiveness) and CLS (visual stability).
  • "Good" thresholds, measured at the 75th percentile of real users: LCP ≤ 2.5 s, INP ≤ 200 ms, CLS ≤ 0.1.
  • Field data (real users) is what counts; lab data (Lighthouse) is for debugging.
  • LCP is usually fixed by faster servers, optimized hero images and fewer render-blocking resources.
  • INP is usually fixed by less JavaScript on the main thread; CLS by reserving space for images, embeds and dynamic content.

The metrics

Metric Measures Good Needs improvement Poor
LCP: Largest Contentful Paint When the largest visible content element renders ≤ 2.5 s 2.5–4.0 s > 4.0 s
INP: Interaction to Next Paint Responsiveness to clicks, taps, key presses across the visit ≤ 200 ms 200–500 ms > 500 ms
CLS: Cumulative Layout Shift Unexpected layout movement ≤ 0.1 0.1–0.25 > 0.25

INP replaced First Input Delay (FID) as a Core Web Vital in 2024. It's stricter, because it considers all interactions rather than just the first one.

Supporting metrics help diagnose problems: TTFB (Time to First Byte), FCP (First Contentful Paint) and Total Blocking Time in lab tests.

Field data vs lab data

  • Field data (RUM): real users on real devices and networks. Sources include the Chrome UX Report (surfaced in PageSpeed Insights and Search Console) and your own real-user monitoring with a library like web-vitals.
  • Lab data: Lighthouse and DevTools in a controlled environment. Great for reproducing and debugging, but it doesn't capture your actual user mix.
jsimport { onLCP, onINP, onCLS } from "web-vitals";

function send(metric) {
  navigator.sendBeacon("/rum", JSON.stringify({
    name: metric.name, value: metric.value, rating: metric.rating, page: location.pathname,
  }));
}
onLCP(send); onINP(send); onCLS(send);

Segment field data by page template, device type and country. Averages hide the pages and users with problems.

Improving LCP (loading)

LCP breaks down into four parts: TTFB → resource load delay → resource load time → render delay. Fix whichever dominates.

1. Reduce TTFB

  • Serve HTML from a CDN or cache it at the edge where possible (what is a CDN).
  • Speed up the backend: caching, fast queries, fewer blocking downstream calls (caching strategies).
  • Use static generation or server rendering for content pages.

2. Make the LCP resource discoverable early

  • The LCP element is often a hero image. Put it in the HTML as a real <img>, not a CSS background or something injected by JavaScript.
  • Add fetchpriority="high" to the hero image, and don't lazy-load it.
  • Preload critical fonts and the LCP image if they're discovered late.

3. Make it smaller

  • Modern formats (AVIF/WebP), correct dimensions, responsive srcset, and compression.

4. Remove render-blocking resources

  • Inline critical CSS; defer non-critical CSS.
  • defer scripts; remove unused JavaScript and third-party tags.
html<img src="/hero-1200.avif"
     srcset="/hero-800.avif 800w, /hero-1200.avif 1200w, /hero-1800.avif 1800w"
     sizes="(max-width: 800px) 100vw, 1200px"
     width="1200" height="630" alt="Product dashboard"
     fetchpriority="high">

Improving INP (responsiveness)

INP measures the time from a user interaction to the next frame being painted. Delays come from three places:

  1. Input delay: the main thread is busy with other work (long tasks) when the user interacts.
  2. Processing time: your event handlers take too long.
  3. Presentation delay: rendering the update (layout, paint) is expensive.

Fixes

  • Ship less JavaScript: code-split, remove unused libraries, and defer third-party scripts (React performance optimization).
  • Break up long tasks: yield to the main thread between chunks of work (for example, await scheduler.yield() where supported, or setTimeout-based chunking).
  • Keep handlers lean: update the UI first (show feedback immediately), then do non-urgent work afterward.
  • Move heavy work off the main thread to Web Workers.
  • Reduce rendering cost: smaller DOMs, avoid layout thrashing, virtualize long lists, and use CSS content-visibility for off-screen sections.
  • In React, use useTransition or useDeferredValue to keep input responsive during expensive updates.

Improving CLS (visual stability)

Layout shifts happen when content moves after it first renders: an image loads and pushes text down, an ad slot expands, a font swap reflows text.

Fixes

  • Always set dimensions (width/height or aspect-ratio) on images, videos and iframes.
  • Reserve space for ads, embeds, banners and dynamically loaded content.
  • Don't insert content above existing content unless the user triggered it (cookie banners should overlay, not push the page).
  • Font loading: use font-display settings plus fallback font metric adjustments (size-adjust) to minimize reflow; preload key fonts.
  • Animate with transforms (transform, opacity) rather than properties that trigger layout (top, height).

Third-party scripts: the silent performance tax

Analytics, tag managers, chat widgets, A/B testing tools and ad scripts frequently dominate main-thread time. Audit them regularly:

  • Remove unused tags.
  • Load non-critical scripts after interaction or when idle.
  • Use lighter alternatives or server-side implementations where possible.

Performance budgets and CI

Prevent regressions:

  • Set budgets: JavaScript bundle size, image weight, LCP and INP targets per template.
  • Run Lighthouse CI or similar checks on pull requests (CI/CD pipeline guide).
  • Alert on field-data regressions from RUM after deploys.

FAQ

Do Core Web Vitals affect Google rankings?

They're part of Google's page experience signals. Content relevance matters far more, but among comparable pages, better user experience can help, and faster pages improve engagement and conversions regardless of rankings.

Why is my Lighthouse score good but my field data poor?

Lighthouse runs on a single simulated device and network. Real users may have slower phones, worse networks, logged-in states or different pages. Prioritize field data and use lab tools to reproduce specific issues.

What's a good TTFB?

As a general guideline, under about 800 ms at the 75th percentile, though faster is better because TTFB directly delays LCP. CDNs and server-side caching are the biggest levers.

Does a single-page application hurt Core Web Vitals?

It can: large JavaScript bundles delay LCP and increase INP. Server rendering or static generation for content pages, code splitting, and careful hydration keep SPAs competitive.