Core Web Vitals: Complete Guide to LCP, INP and CLS in 2026
LCP, INP and CLS explained with practical code examples. Optimize each metric and keep Page Experience in the green.

Load speed is no longer just a user experience issue — it became an official Google ranking factor. Since 2021, Core Web Vitals have been part of the algorithm, and in March 2024 Google replaced FID (First Input Delay) with INP (Interaction to Next Paint). In 2026, these three metrics —LCP, INP and CLS— define, in practice, the perceived quality of your page, both for rankings and conversions.
If your page takes more than 2.5 seconds to load the main content, freezes when receiving clicks or "jumps" while the user reads, you are losing rankings and sales. This guide shows exactly how to measure, diagnose and fix each of the three metrics, with practical HTML, CSS and JavaScript code examples.
What Are Core Web Vitals
Core Web Vitals are a set of metrics defined by Google to measure the real experience of loading, interactivity and visual stability of pages. There are three, each measuring a different aspect:
| Metric | What it measures | Good | Needs improvement | Poor |
|---|---|---|---|---|
| LCP | Largest visible content render | up to 2.5s | up to 4.0s | over 4.0s |
| INP | Responsiveness to interactions | up to 200ms | up to 500ms | over 500ms |
| CLS | Visual stability during load | up to 0.1 | up to 0.25 | over 0.25 |
| Google's rule is clear: to pass the assessment, the page must be in the "good" range for 75% or more of visits, considering a 28-day window. | ||||
| INP Replaced FID | ||||
| FID measured only the delay until the first interaction. INP goes further: it measures the response time of every interaction the user makes on the page —clicks, taps and key presses— and reports the worst one (usually p95). A page can have a fast first interaction and still freeze in the middle of navigation; INP captures exactly that. | ||||
| In 2026, INP is one of the most neglected metrics and one of those that most affects conversion on sites with heavy JavaScript. | ||||
| How to Measure Core Web Vitals | ||||
| You don't need to guess. There are four main measurement methods, each with a purpose: | ||||
| PageSpeed Insights (PSI) — spot analysis of any URL, with lab and field data. Start here. | ||||
| Google Search Console — "Core Web Vitals" report with real field data from your users, by URL group. | ||||
| Chrome DevTools — for fine debugging, especially with the "Performance" panel and integrated Lighthouse. | ||||
| RUM (Real User Monitoring) — tools like Web Vitals JS, Cloudflare RUM or Vercel Analytics, which tracks real users on your site. | ||||
| Capturing Web Vitals in the Browser | ||||
You can measure in real time using the official web-vitals library: | ||||
<script src="https://unpkg.com/web-vitals@4/dist/web-vitals.iife.js"></script>
<script>
const vitals = {};
function reportVital(metric) {
vitals[metric.name] = metric.value;
console.log(`${metric.name}: ${metric.value}`);
}
webVitals.onCLS(reportVital);
webVitals.onLCP(reportVital);
webVitals.onINP(reportVital);
</script>In a production environment, you would send these values to your analytics tool to build a real-time performance dashboard.
LCP: Optimizing Largest Contentful Paint
LCP measures the time it takes for the largest visible element in the viewport to be rendered. Most of the time, this element is a hero image, a video, or a large block of text. A poor LCP means the user is left staring at a blank or partially loaded screen.
Main Causes of Poor LCP
- Slow server — high TTFB (above 800 ms)
- Heavy hero image — not optimized, in a legacy format
- CSS blocking rendering — large, non-critical stylesheets
- JavaScript blocking rendering — scripts in the header preventing the browser from rendering
- Prefetch/render without prioritization — the browser downloads unimportant elements before the main content
How to Fix: HTML and CSS
1. Optimize and Prioritize the Hero Image
<!-- Before: heavy JPEG, no dimensions, loaded last -->
<img src="hero.jpg" alt="Banner">
<!-- After: WebP, with dimensions and preload -->
<link rel="preload" as="image" href="/img/hero-1200.webp">
<img
src="/img/hero-1200.webp"
alt="Main banner"
width="1200"
height="675"
fetchpriority="high"
>The fetchpriority="high" attribute instructs the browser to prioritize downloading that image. width and height prevent CLS. preload triggers the download as early as possible.
2. Load Critical CSS Inline
Instead of blocking rendering with all the CSS, deliver only the essential CSS for the first paint:
<style>
/* Critical CSS: header, hero, above-the-fold */
.hero { display: grid; place-items: center; min-height: 60vh; }
.hero-title { font-size: clamp(1.8rem, 4vw, 3.5rem); }
</style>
<!-- Rest of CSS loaded asynchronously -->
<link rel="preload" href="/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/main.css"></noscript>This pattern (inline critical CSS + asynchronous CSS) drastically reduces the first-paint time without compromising the full design.
3. Improve TTFB on the Server
- Enable caching on HTTP responses.
- Use CDN to serve static content from locations close to the user.
- For webNode.js/Next.jss, consider edge rendering and streaming.
- On Apache or Nginx, enable gzip or Brotli:
# Nginx: Brotli compression
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;4. Lazy Load Only Content Below the Fold
<img
src="product-a.jpg"
alt="Product A"
loading="lazy"
decoding="async"
width="600"
height="400"
>Warning: Never use loading="lazy" on the hero image. It must load first.
INP: Making the Page Responsive to Interactions
INP measures the latency of all interactions: the time between a user's click and the visual response. The main culprit behind INP is almost always long, blocking JavaScript on the main thread.
Common Causes of Poor INP
- Heavy JavaScript on load that keeps executing and "steals" the thread
- Slow event listeners that perform heavy synchronous work
- Unnecessary reflows triggered with every interaction
- Animations blocking the main thread instead of using CSS or Web Workers
- Third-party scripts (analytics, chat, pixel) performing intensive work
How to Fix: JavaScript
1. Break Down Long Tasks Using setTimeout or scheduler.yield()
If you process many items at once, the browser freezes:
// Before: blocks thread for hundreds of ms
const items = await fetchData();
for (const item of items) {
renderItem(item);
}
// After: split the work into microtasks
const items = await fetchData();
for (const item of items) {
setTimeout(() => renderItem(item), 0);
}Even better, use the new browser API:
for (const item of items) {
if (typeof scheduler !== 'undefined' && scheduler.yield) {
await scheduler.yield();
}
renderItem(item);
}2. Debounce and Throttle Listeners
let timeoutId;
input.addEventListener('input', () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => filterResults(input.value), 300);
});3. Avoid Reflows in the Middle of Layout Reading
// Bad: reads and writes DOM alternately, causing reflow each cycle
for (const el of list) {
const height = el.offsetHeight; // read
el.style.height = height + 10 + 'px'; // write
}
// Good: read everything first, then write
const heights = list.map(el => el.offsetHeight);
list.forEach((el, i) => { el.style.height = heights[i] + 10 + 'px'; });4. Use Web Workers for Heavy Processing
Data processing, parsing, and complex calculations should not run on the main thread:
// main.js
const worker = new Worker('/js/processor.js');
worker.postMessage({ data: rawData });
worker.onmessage = (event) => { displayResult(event.data); };
// processor.js
self.onmessage = (event) => {
const result = heavyProcess(event.data.data);
self.postMessage(result);
};5. Load Third-Party Scripts with Caution
Chat, pixels, and analytics tools are largely responsible for poor INP. Load them asynchronously and only when needed:
<script async src="https://cdn.chat.com/widget.js"></script>You should also consider deferring the initialization of those widgets until the user interacts with them:
document.addEventListener('scroll', () => { loadChatWidget(); }, { once: true });The Special Case of JavaScript Frameworks
In React, Vue, or Next.js, INP is usually affected by:
- Many components hydrating at once — consider Server Components or partial hydration.
- Poorly split global state — each change causes unnecessary components to re-render.
- Large lists — use virtualization (react-window, virtual) instead of rendering 1,000 items.
CLS: Visual Stability Without Surprises
CLS (Cumulative Layout Shift) measures how much elements "jump" on the screen during loading. A reading session that shifts, a button that moves when clicked, and images that appear only after the text are all examples of CLS.
Common Causes of CLS
- Images without
widthandheight - Iframes, embedded videos, and ads without reserved space
- Fonts that load late and cause layout shifts (FOUT)
- Dynamic content insertion in the middle of the page
- Animations that alter layout properties (height, width, top)
How to Fix: HTML and CSS
1. Set Aside Space for Images and Videos
<!-- Before: no dimensions, causes CLS on load -->
<img src="photo.jpg" alt="Photo">
<!-- After: with dimensions, browser reserves space -->
<img
src="photo.jpg"
alt="Photo"
width="1200"
height="800"
style="width: 100%; height: auto;"
>2. Use aspect-ratio in CSS for Responsive Layouts
.video-container {
aspect-ratio: 16 / 9;
width: 100%;
}
.card-img {
aspect-ratio: 4 / 3;
object-fit: cover;
width: 100%;
}3. Reserve Space for Dynamic Content and Ads
/* Instead of injecting a banner that pushes content, reserve space */
.ad-slot {
width: 300px;
height: 250px; /* reserved space */
background: #f0f0f0;
}4. Load Fonts with font-display: swap and size-adjust
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
font-display: swap;
}
/* Fix shift caused by font swap */
h1 {
font-family: 'MyFont', sans-serif;
font-size-adjust: 0.5;
}font-display: swap shows the fallback font immediately and swaps later; combined with size-adjust or font-size-adjust, the swap causes no perceptible jump.
5. Safe Animations That Don't Cause Layout Shifts
Animate only the transform and opacity properties: they do not cause a reflow:
/* Bad: touches layout, causes CLS and jank */
.popup { top: 0; transition: top 0.3s; }
/* Good: uses `transform`, no impact on layout */
.popup { transform: translateY(100%); transition: transform 0.3s; }
.popup.open { transform: translateY(0); }Resource Prioritization with the Browser
A technique that optimizes LCP, INP, and CLS all at once is correct resource prioritization. The browser downloads resources in an order that you can control:
<!-- 1. Critical CSS (blocks paint, must be first) -->
<link rel="preload" as="style" href="/css/critical.css">
<!-- 2. Hero image -->
<link rel="preload" as="image" href="/img/hero.webp" fetchpriority="high">
<!-- 3. Fonts used above the fold -->
<link rel="preload" as="font" type="font/woff2" href="/fonts/heading.woff2" crossorigin>
<!-- 4. Essential JavaScript, without blocking render -->
<script src="/js/app.js" defer></script>Impact of Core Web Vitals on SEO and Conversions
Google officially announced that pages with "good" Core Web Vitals are prioritized over equivalent pages with poor metrics. In 2026, with INP consolidated, the practical impact is clear:
- Slow pages lose rankings to equivalent faster pages.
- INP directly affects conversion: sites with instant response times convert more visitors.
- Google groups URLs in Search Console: those with “poor” vitals are flagged for correction.
- Crawl budget: faster sites are crawled more often, resulting in more pages being indexed.
Internal agency data (such as TS Digitais, which audits the performance of dozens of websites) shows a consistent pattern: improving Core Web Vitals is usually accompanied by higher rankings and, above all, an increase in conversion rates: users don't make purchases on websites that freeze.
Step-by-Step Optimization Workflow
Follow this sequence to optimize any website:
- Measure — run PageSpeed Insights on the main URL and sales pages.
- Prioritize — fix the worst metric of the most important page first.
- Diagnose — open Chrome DevTools > Performance and record a real session.
- Fix — apply the HTML/CSS/JS corrections from this guide.
- Validate — rerun PSI and compare the lab score.
- Monitor — confirm improvement in Search Console field data within 28 days.
Core Web Vitals Checklist
preload and fetchpriority="high"width, height and loading="lazy" when below the foldfont-display: swap and preload of essential variationsdefer or async, no render blockingsetTimeout, scheduler.yield())transform and opacityFAQ
What is INP and why did it replace FID?
INP (Interaction to Next Paint) measures the browser's response time to all user interactions—clicks, taps, and typing—and reports the worst latency. FID measured only the delay of the first interaction. Since a page can have a good initial response but freeze later, Google replaced FID in March 2024 to provide a more complete picture of a page’s actual responsiveness. A “good” value is up to 200 ms.
What is a good value for each Core Web Vital in 2026?
LCP up to 2.5 seconds, INP up to 200 ms, and CLS up to 0.1. To pass Google's assessment, your page must meet these values on at least 75% of visits, as measured by 28-day field data. Intermediate values are classified as "needs improvement," and higher values as "poor."
How to optimize LCP when the hero image is the problem?
Convert the image to WebP or AVIF, resize it to the actual display size, add preload and fetchpriority="high", and consider using a CDN with edge caching. If the image is illustrative, another option is to replace it with pure CSS or a gradient. Also measure TTFB: if the server takes more than 800 ms to respond, image optimization alone won’t fix the issue.
Is CLS still relevant after the page loads?
Yes. CLS measures layout shifts throughout the entire lifespan of the page, not just upon load. Buttons that appear in the middle of the text, pop-ups that disrupt the layout, and lazy-loaded images without reserved space can cause CLS even minutes after the page loads. The good news is that 75% of shifts on a typical page occur within the first 5 seconds.
Is it worth optimizing Core Web Vitals on a small site with little traffic?
Yes. Beyond their direct impact on rankings, Core Web Vitals are an indicator of user experience, and that experience influences conversion rates, bounce rates, and brand trust. A fast site conveys professionalism. And since Google prioritizes fast pages over equivalent pages, optimizing performance is one of the few SEO advantages you have 100% control over, without relying on backlinks or domain authority.
Article written by Tiago Silva Dal Bosco, founder of TS Digitais.
Tiago Silva Dal Bosco
Founder & SEO Specialist


