Core Web Vitals are Google’s attempt to put numbers on something every visitor feels instinctively: does the page show up quickly, does it react when I tap, and does it stop jumping around? In 2026 the set is stable — Largest Contentful Paint (LCP), Interaction to Next Paint (INP) and Cumulative Layout Shift (CLS) — and the tooling has matured enough that there is little mystery left in how to improve them. What remains is the work. This guide explains what each metric really measures, how to read the data without fooling yourself, and the specific fixes we reach for first when a site is failing.
What Core Web Vitals actually measure#
Each of the three metrics targets a different part of the user experience. They are deliberately user-centric: instead of measuring when a server finishes sending bytes, they measure moments a person would notice.
- Largest Contentful Paint (LCP) marks when the largest image or text block in the viewport is rendered. It is a proxy for “the main content has arrived”.
- Interaction to Next Paint (INP) observes the latency of clicks, taps and key presses during the whole visit and reports one of the slowest. It measures the time from the input until the browser paints the next frame showing a response.
- Cumulative Layout Shift (CLS) sums unexpected layout shifts, grouped into session windows, and reports the worst window. It quantifies how much the page jumps around under the reader’s eyes.
INP officially replaced First Input Delay (FID) on 12 March 2024. FID only measured the delay before the browser started handling the first interaction, which almost every site passed. INP covers the full round trip — input delay, event handler processing and rendering — for every interaction, which is why many sites that looked fine under FID suddenly found themselves in the “needs improvement” bucket.
| Metric | Good | Needs improvement | Poor | Main causes of failure |
|---|---|---|---|---|
| LCP | ≤ 2.5 s | 2.5–4.0 s | > 4.0 s | Slow server response, late-discovered hero image, render-blocking CSS/JS |
| INP | ≤ 200 ms | 200–500 ms | > 500 ms | Long JavaScript tasks, heavy third-party scripts, large DOM updates |
| CLS | ≤ 0.1 | 0.1–0.25 | > 0.25 | Images without dimensions, late-injected banners and ads, web font swaps |
A page “passes” when all three metrics are in the good range at the 75th percentile of real page loads, assessed separately for mobile and desktop. That percentile matters: it means three out of four visits need to be good, so you cannot hide a slow experience for mobile users behind a fast office connection. The official definitions live in Google’s Web Vitals overview on web.dev.
Field data vs lab data: read the right numbers#
The single most common mistake we see is optimizing for the wrong data source. There are two fundamentally different kinds of measurements.
Field data (what Google uses)#
Field data comes from real users. Google’s public dataset is the Chrome UX Report (CrUX), collected from opted-in Chrome users and aggregated over a rolling 28-day window. It is what you see in the “Discover what your real users are experiencing” panel of PageSpeed Insights and in the Core Web Vitals report in Google Search Console. When people talk about “passing Core Web Vitals”, this is the data they mean.
Low-traffic pages may have no CrUX data, so tools fall back to origin-level data for the whole site. And because of the 28-day window, today’s fix takes about four weeks to fully show up.
Lab data (what you debug with)#
Lighthouse, the PageSpeed Insights lab section and the Chrome DevTools Performance panel run a page load in a controlled environment. Lab data is reproducible and great for diagnosing why something is slow, but it is not what is assessed. Lab tests also cannot measure INP properly, because nobody is clicking anything; Total Blocking Time (TBT) is the closest lab proxy, since long main-thread tasks during load are what make early interactions sluggish.
- Use field data to decide what to fix and lab tools to understand how to fix it.
- Always check mobile first: it is almost always the worse of the two, and it is the experience most of your visitors have.
- Throttle the CPU in DevTools (4x or 6x slowdown) when debugging; your laptop is not a mid-range phone.
How much do Core Web Vitals affect SEO?#
Core Web Vitals are part of Google’s page experience signals, and Google has been consistent in its messaging: relevance and content quality come first, and great Core Web Vitals do not guarantee top rankings. Google’s own Search Central documentation recommends achieving good Core Web Vitals for success with Search and for a good user experience generally, without promising a ranking boost.
Think of performance as something that removes friction rather than something that creates rankings: a faster, more stable page is simply more pleasant to use and buy from. If you are launching a new site, performance belongs on the same list as crawlability and indexation; our technical SEO checklist for new websites puts it in that context.
Optimizing Largest Contentful Paint#
Stop treating LCP as one number. Google breaks it into four sub-parts, each pointing to a different fix:
- Time to First Byte (TTFB) — how long until the first byte of HTML arrives.
- Resource load delay — the gap between TTFB and when the browser starts downloading the LCP resource (usually an image).
- Resource load duration — how long that download takes.
- Element render delay — the time between the resource finishing and the element actually being painted.
Google’s guidance is that on a well-optimized page most of the time should be spent on TTFB and the resource download itself, with the two “delay” phases kept very small. If your load delay or render delay is large, you have a discovery or blocking problem, not a bandwidth problem.
Find the LCP element first#
Open the DevTools Performance panel, record a page load and look for the LCP marker; it highlights the element. On most marketing pages it is a hero image, a large heading or a background image set in CSS. Background images are a common trap because the browser cannot discover them until the CSS has been downloaded and parsed.
Reduce TTFB#
Server response time is the foundation. Full-page caching (at the server or a CDN edge), a nearby CDN point of presence, efficient database queries and up-to-date PHP versions all help. For dynamic sites such as WordPress, a page cache is usually the biggest single LCP win available. If your hosting is the bottleneck, our comparison of static, managed WordPress and VPS hosting explains where each option shines.
Make the LCP resource discoverable and prioritized#
The browser’s preload scanner finds <img> tags in the HTML early, so a real image element beats a CSS background. Never lazy-load the LCP image, and tell the browser it matters with fetchpriority="high":
<!-- Hero image: eager, high priority, explicit dimensions -->
<img
src="/images/hero-1200.avif"
srcset="/images/hero-800.avif 800w, /images/hero-1200.avif 1200w, /images/hero-1600.avif 1600w"
sizes="(max-width: 800px) 100vw, 1200px"
width="1200" height="630"
alt="Dashboard showing monthly revenue by channel"
fetchpriority="high">
<!-- If the image is only referenced from CSS, preload it instead -->
<link rel="preload" as="image" href="/images/hero-1200.avif" fetchpriority="high">
Keep loading="lazy" for images below the fold. Many WordPress themes and plugins lazy-load everything by default, including the hero; WordPress core itself tries to avoid this by skipping lazy-loading for the first content images and, since version 6.3, by adding fetchpriority="high" to the image it judges most likely to be the LCP element — but themes, builders and optimization plugins can override that behaviour.
Shrink the download#
Serve AVIF or WebP, size images for their slot with srcset and sizes, and cache them on a CDN. An oversized hero on a congested mobile connection can consume most of the 2.5-second budget by itself.
Remove render blockers#
Render-blocking stylesheets and synchronous scripts in the <head> delay the first paint even after the image has arrived. Inline the small amount of critical CSS needed for above-the-fold content, load scripts with defer or type="module", and make sure web fonts do not hide text: font-display: swap (or optional) keeps text-based LCP elements visible.
Optimizing Interaction to Next Paint#
INP is where most sites struggle in 2026, because it is fundamentally about JavaScript discipline. Every interaction goes through three phases, and you need to know which one is slow:
- Input delay — the main thread is busy with something else (often a third-party script or hydration) when the user taps.
- Processing duration — your event handlers themselves take too long.
- Presentation delay — after handlers finish, the browser needs a long time to recalculate styles, lay out and paint, often because the DOM is huge or the update touches too much of it.
The INP value reported for a page is close to its worst interaction (for pages with very many interactions, a few outliers are ignored). Only discrete interactions count: clicks, taps and key presses. Scrolling and hovering do not. Google’s INP documentation walks through each phase in detail.
Break up long tasks#
The browser cannot paint while JavaScript is running. Any task longer than 50 ms is considered a “long task”, and a click handler that runs for 300 ms guarantees a poor INP for that interaction. The fix is to do the minimum needed for visual feedback first, then yield to the main thread before doing the rest:
// Yield to the main thread so the browser can paint.
// scheduler.yield() is available in Chromium-based browsers; fall back to setTimeout elsewhere.
function yieldToMain() {
if (globalThis.scheduler?.yield) {
return scheduler.yield();
}
return new Promise((resolve) => setTimeout(resolve, 0));
}
filterForm.addEventListener('change', async (event) => {
// 1. Immediate visual feedback
resultsRegion.setAttribute('aria-busy', 'true');
statusText.textContent = 'Updating results…';
// 2. Let the browser paint that feedback
await yieldToMain();
// 3. Do the expensive work afterwards
const items = applyFilters(allProducts, new FormData(filterForm));
renderResults(items);
resultsRegion.removeAttribute('aria-busy');
});
Audit third-party scripts#
Tag managers, chat widgets, A/B testing tools, heatmaps and ad scripts all compete for the same main thread. They frequently cause input delay on interactions that have nothing to do with them. Inventory every script, remove what nobody uses, delay non-essential widgets until after the first interaction or until the browser is idle, and load the rest with defer.
Keep DOM updates small#
Presentation delay grows with the amount of layout work. Avoid re-rendering a whole list when one item changes, avoid reading layout properties (like offsetHeight) immediately after writing styles, which forces synchronous layout, and consider content-visibility: auto for long off-screen sections so the browser can skip rendering them. Pages with many thousands of DOM nodes — common with page builders and mega menus — are slower to update no matter how efficient the script is.
Question the framework#
Frameworks that hydrate the whole page on load create long tasks precisely when visitors start interacting. For content sites and many storefronts, server-rendered HTML with small, targeted scripts is often faster, as we argue in Modern JavaScript Without the Bloat.
Optimizing Cumulative Layout Shift#
CLS is usually the easiest of the three to fix, because the causes are concrete and visible. A layout shift happens when an element that is already visible changes position without the user causing it. Shifts that occur within 500 ms of a user interaction are excluded, which is why expanding an accordion on click does not hurt you.
Reserve space for everything that loads later#
- Images and video: always include
widthandheightattributes. Modern browsers use them to compute an aspect ratio before the file arrives, even when CSS makes the image responsive. - Embeds, ads and iframes: give their containers a fixed or minimum height, or use the CSS
aspect-ratioproperty. - Cookie banners and promo bars: overlay them (fixed position) rather than pushing content down after the page has painted.
/* Reserve space for a responsive 16:9 video embed */
.video-embed {
aspect-ratio: 16 / 9;
width: 100%;
background: #111;
}
/* Keep fallback and web font metrics close to avoid text reflow */
@font-face {
font-family: "Brand Sans Fallback";
src: local("Arial");
size-adjust: 104%;
ascent-override: 92%;
descent-override: 24%;
}
Tame web fonts#
When a web font replaces a fallback font with different metrics, every line of text can re-wrap. Preload the one or two font files used above the fold, self-host them, and use size-adjust and the metric override descriptors so the fallback occupies the same space as the final font.
Animate with transforms#
Animating top, left, height or margin moves other elements and counts as layout shift. Animating transform and opacity does not, and it is cheaper for the browser too.
Benefit from the back/forward cache#
Pages restored from the back/forward cache (bfcache) appear instantly and stable. unload listeners and Cache-Control: no-store on HTML make pages ineligible; the bfcache test in the DevTools Application panel shows what is blocking yours.
Measuring with real-user monitoring#
You do not need an expensive product to collect your own field data. Google’s open-source web-vitals JavaScript library measures the metrics the same way Chrome does, and a few lines of code can send them to an endpoint or your analytics tool:
import { onLCP, onINP, onCLS } from 'web-vitals';
function sendToAnalytics(metric) {
const body = JSON.stringify({
name: metric.name, // 'LCP' | 'INP' | 'CLS'
value: metric.value,
rating: metric.rating, // 'good' | 'needs-improvement' | 'poor'
id: metric.id,
page: location.pathname,
navigationType: metric.navigationType,
});
// sendBeacon survives page unloads; fall back to fetch with keepalive
if (!navigator.sendBeacon?.('/vitals', body)) {
fetch('/vitals', { body, method: 'POST', keepalive: true });
}
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
The library also ships an “attribution” build that reports which element was the LCP, which interaction produced the worst INP and which element shifted — turning “INP is poor on product pages” into “the size selector’s handler is slow on Android”, which a developer can actually fix. Aggregate at the 75th percentile per page template, never as averages: averages hide exactly the slow tail that CrUX measures.
Core Web Vitals on WordPress and WooCommerce#
On WordPress sites the failure patterns are remarkably consistent:
- No full-page cache, so every visit waits for PHP and MySQL. This shows up as high TTFB and poor LCP.
- Page builders and multipurpose themes that load large CSS and JavaScript bundles on every page and generate deeply nested DOM trees. These hurt both LCP and INP.
- Plugin sprawl: sliders, popups, social feeds and analytics add-ons each enqueue their own assets globally, even on pages that do not use them.
- Optimization plugins fighting each other, for example two plugins both minifying, combining or lazy-loading the same assets, sometimes breaking scripts and causing shifts.
Stores have additional dynamic elements — mini carts, live search, variation pickers, cart fragments — that are both INP-sensitive and harder to cache. We cover those specifically in our guide to WooCommerce performance. Clean markup also helps: a lean, semantic DOM is faster to style and update, which is one more reason to care about semantic HTML.
A prioritized workflow that works#
When a site fails, resist the urge to install another plugin and hope. Work through it in order:
- Check field data in Search Console and PageSpeed Insights: which metric fails, on which device, for which URL groups.
- Group pages by template. Fixing the product template fixes hundreds of URLs at once.
- Diagnose in the lab with throttling: the LCP element and its sub-parts, long tasks and their scripts, shifting elements.
- Fix the foundations first: caching and TTFB, then LCP priority, then JavaScript weight and third parties.
- Verify with real-user data, and expect CrUX to follow over four weeks.
- Prevent regressions with a performance budget checked on every deployment.
- Core Web Vitals in 2026 are LCP (≤ 2.5 s), INP (≤ 200 ms) and CLS (≤ 0.1), judged at the 75th percentile of real visits.
- Optimize against field data; use lab tools only to diagnose.
- LCP is mostly about server response and getting the hero resource discovered and prioritized early.
- INP is about main-thread discipline: fewer scripts, shorter tasks, smaller DOM updates.
- CLS is about reserving space: dimensions on media, stable containers for late content, matched font metrics.
Conclusion: performance is a habit, not a project#
Core Web Vitals reward restraint: lean HTML, prioritized resources, purposeful JavaScript and layouts that reserve space for what is coming. None of these fixes are exotic; the hard part is knowing which cause is responsible on your site, and keeping it fixed as plugins and marketing tags accumulate.
If you would like an expert pair of eyes on your numbers, our Performance & Technical SEO Audit analyzes your field and lab data template by template and gives you a prioritized, developer-ready list of fixes. Prefer to talk it through first? Get in touch with us and tell us what you are seeing.
Frequently asked questions
What are the current Core Web Vitals thresholds?
A page passes when, at the 75th percentile of real visits, Largest Contentful Paint is 2.5 seconds or less, Interaction to Next Paint is 200 milliseconds or less, and Cumulative Layout Shift is 0.1 or less. Google evaluates mobile and desktop separately.
Did INP replace First Input Delay?
Yes. Interaction to Next Paint officially replaced First Input Delay as a Core Web Vital on 12 March 2024. INP is stricter because it looks at the full latency of interactions throughout the visit, not just the input delay of the first one.
Why does PageSpeed Insights show a good Lighthouse score but failing Core Web Vitals?
Lighthouse is a lab test run once on a simulated device, while the Core Web Vitals assessment uses field data from real Chrome users over the previous 28 days. Real visitors have slower phones, worse networks and interact with the page, so field results are often worse than a single lab run.
How long does it take for Core Web Vitals improvements to show up?
The Chrome UX Report uses a rolling 28-day window, so after you deploy a fix the field numbers improve gradually over about four weeks. Your own real-user monitoring can confirm the change within days.
