Core Web Vitals in Plain English: LCP, INP, CLS and the Fixes That Matter Most

Core Web Vitals are three measurements Google uses to describe how a page feels to real users: how quickly the main content appears, how quickly the page responds when you interact with it, and how much the layout jumps around. They are part of Google's page experience signals. They will not lift a page with weak content over a better answer, but they do affect conversion and bounce rates on every site, which is reason enough to fix them.

This guide explains each metric without jargon, explains why your PageSpeed score and your Search Console report often disagree, and lists the fixes that make the biggest difference in practice.

The three metrics and their thresholds

Each metric is judged at the 75th percentile of real page loads over the previous 28 days, separately for mobile and desktop. That means three out of four visits must hit the "good" mark for the page to pass.

  • Largest Contentful Paint (LCP): time until the largest image or text block in the viewport is rendered. Good is 2.5 seconds or less; poor is over 4 seconds.
  • Interaction to Next Paint (INP): the delay between a click, tap, or key press and the next visual update, taken across the whole visit (roughly the worst interaction). Good is 200 milliseconds or less; poor is over 500 ms. INP replaced First Input Delay as a Core Web Vital in March 2024.
  • Cumulative Layout Shift (CLS): a score for unexpected movement of visible content. Good is 0.1 or less; poor is over 0.25. Shifts within 500 ms of a user interaction, such as expanding an accordion, do not count.

Lab data vs field data

Field data comes from real Chrome users through the Chrome User Experience Report (CrUX). It is what Search Console shows and what Google uses. Lab data comes from a single simulated load in Lighthouse, typically on an emulated mid-range phone with throttled network.

They disagree for good reasons. Lab tests load one URL once with an empty cache, while real users have warm caches, faster or slower devices, and arrive on different pages. Lab tests also cannot measure INP because nobody clicks anything; Lighthouse reports Total Blocking Time (TBT) as a proxy. A good TBT usually means a better INP, but not always.

Use field data to decide what to fix and lab data to diagnose why. If CrUX has no data for a URL because traffic is low, Search Console groups similar URLs together, and you can collect your own field data with the web-vitals JavaScript library.

import { onLCP, onINP, onCLS } from 'web-vitals';

function send(metric) {
  navigator.sendBeacon('/analytics/vitals', JSON.stringify({
    name: metric.name, value: metric.value, rating: metric.rating, page: location.pathname
  }));
}

onLCP(send);
onINP(send);
onCLS(send);

Fixing LCP

LCP breaks into four parts: time to first byte (server response), resource load delay (how long before the browser starts fetching the LCP image), resource load duration (download time), and element render delay (time from download to paint). Open the Performance panel in Chrome DevTools or a PageSpeed Insights report to see which part dominates before changing anything.

  • Make the LCP image discoverable in the HTML. If it is set as a CSS background or injected by JavaScript, the browser finds it late. Use a regular img element.
  • Never lazy-load the LCP image. Remove loading="lazy" from above-the-fold hero images and add fetchpriority="high".
  • Compress and size the image correctly. A 2 MB hero photo on mobile is the most common LCP problem; serve WebP or AVIF at the displayed width using srcset.
  • Reduce server response time with caching or a CDN. A TTFB over about 800 ms leaves little room for everything else.
  • Remove render-blocking CSS and JavaScript in the head, and preconnect to any third-party origin that serves the LCP resource.

Fixing INP

Poor INP almost always means the main thread is busy when the user interacts. Any task longer than 50 ms is a "long task" and blocks input handling until it finishes. Third-party scripts such as tag managers, chat widgets, and A/B testing tools are frequent offenders, along with large framework re-renders.

  • Do the visible part of an event handler first, then defer the rest. Update the button state, then yield before analytics calls or heavy computation.
  • Break long tasks into chunks. scheduler.yield() is available in Chromium-based browsers; fall back to setTimeout(resolve, 0) elsewhere.
  • Audit third-party scripts in DevTools and remove what nobody uses. Load the rest with async or defer.
  • Avoid re-rendering large lists on every keystroke. Debounce input handlers and virtualise long lists.
  • Keep the DOM reasonably small. Very large DOMs make every style and layout recalculation slower.
async function onSaveClick() {
  button.disabled = true;          // visible feedback first
  label.textContent = 'Saving...';
  await yieldToMain();              // let the browser paint
  await saveDraft();                // then the expensive work
  trackEvent('save');
}

function yieldToMain() {
  if (globalThis.scheduler?.yield) return scheduler.yield();
  return new Promise((resolve) => setTimeout(resolve, 0));
}

Fixing CLS

Layout shift happens when something appears or resizes without space reserved for it. The fixes are mostly about reserving that space in advance.

  • Give every image and video width and height attributes (or a CSS aspect-ratio) so the browser reserves the box before the file loads.
  • Reserve fixed-height slots for ads, embeds, and cookie banners. Collapsing an empty ad slot after load causes a shift too.
  • Do not insert banners or notices above existing content after the page has rendered; overlay them or place them below.
  • Reduce font swap shifts by preloading the main web font and using size-adjust or a closely matched fallback font.
  • Animate with transform and opacity, not top, left, width, or height.
  • Keep pages eligible for the back/forward cache (avoid unload handlers), so back navigation is instant and shift-free.

Where to start

Open the Core Web Vitals report in Search Console, pick the URL group with the most traffic in the poor bucket, and run a representative URL through PageSpeed Insights (the Neemtools Page Speed Insights tool runs the same test). In most audits, the first two fixes are the same: compress and correctly size the hero image, and remove or defer a third-party script. After deploying, remember the field data is a 28-day rolling window, so improvements take up to four weeks to show fully in Search Console.