Core Web Vitals dashboard showing LCP, INP, and CLS scores with fix recommendations
Web Performance

Core Web Vitals Failing — How to Diagnose and Fix LCP, INP, and CLS

Sunny Pal Singh · · 7 min read

Core Web Vitals failures show up in Google Search Console as red — but the report doesn't tell you why they're failing or what to fix first. The three metrics measure different things (load, interactivity, visual stability), fail for different reasons, and require different fixes. This guide breaks down the root causes and the specific changes that actually move the scores.

Google Search Console groups Core Web Vitals failures by metric and affected URL — but it doesn't explain the cause. A red LCP could mean a slow server, a lazy-loaded hero image, a render-blocking stylesheet, or an image sitting inside a CSS background. The fix for each is completely different. Diagnosing without knowing which cause applies wastes hours.

This guide treats LCP, INP, and CLS as separate problems because they are. Each metric has its own failure patterns, its own diagnostic signals, and its own set of fixes. Work through each one independently rather than applying performance advice generically.

Key Takeaways

  • LCP (Largest Contentful Paint) should be under 2.5s — usually fixed by lazy-loading removal, preloading the hero image, or improving server TTFB
  • INP (Interaction to Next Paint) should be under 200ms — caused by long JavaScript tasks blocking the main thread; fixed by code-splitting and deferring non-critical JS
  • CLS (Cumulative Layout Shift) should be under 0.1 — caused by images without dimensions, dynamically injected content, and web fonts causing FOUT
  • Field data (from real users via CrUX) matters more than lab data (Lighthouse) for Google's ranking signal
  • Fix LCP first — it has the most direct impact on perceived performance and is usually the easiest to improve

The Three Metrics and Their Thresholds

Metric Good Needs Improvement Poor
LCP ≤ 2.5s 2.5–4.0s > 4.0s
INP ≤ 200ms 200–500ms > 500ms
CLS ≤ 0.1 0.1–0.25 > 0.25

Google's "pass" threshold is 75% of page loads in the "Good" range. Failing means fewer than 75% of real-user visits meet the threshold — not just that your Lighthouse score missed the mark.

Fixing LCP

LCP measures when the largest visible element — usually an image, video poster, or large text block — finishes loading. It is the metric most directly tied to perceived load speed and the one most sites fail to hit on the first attempt.

Slow server response (TTFB > 600ms). Everything starts with the server. If the time to first byte is slow, LCP cannot be fast regardless of what you do on the client. Use the Page Speed Inspector to measure TTFB directly — it runs a fresh socket request and reports DNS, TCP, TLS, and TTFB as separate timings so you know exactly where the delay sits.

LCP image not preloaded. If the LCP element is an image, it won't start loading until the browser discovers it in the HTML. Add a preload hint in <head>:

<link rel="preload" as="image" href="/hero.jpg" fetchpriority="high">

And add fetchpriority="high" to the <img> element itself. This tells the browser to prioritise this image over lower-priority resources in the same load phase.

LCP image is lazy-loaded. Remove loading="lazy" from the LCP image. The browser defers lazy-loaded images until they are near the viewport — which for the hero image on page load means a meaningful delay. Lazy loading is correct for below-fold images, but actively harmful for the LCP element.

LCP image in a CSS background. Browsers don't preload CSS background images — the preload scanner only finds <img> tags. Move the LCP element to an HTML <img> tag so the scanner can discover it before the CSS is fully parsed. If keeping it as a background image, you must use <link rel="preload" as="image"> manually to compensate.

Render-blocking resources. JS and CSS in <head> without defer or async delays the first paint. Every millisecond of render-blocking time is added directly to LCP. Use defer on non-critical scripts and inline the minimum critical CSS needed to render above-the-fold content. The Page Speed Inspector flags render-blocking scripts and stylesheets under its recommendations.

Fixing INP

INP (Interaction to Next Paint) replaced FID as a Core Web Vital in March 2024. Where FID measured the delay before the browser could even start processing a user's first input, INP measures the delay from any interaction — click, key press, tap — to the next visual update. A slow INP makes the page feel unresponsive after the initial load.

Long tasks blocking the main thread. JavaScript tasks over 50ms block user interactions. When a user clicks a button while a 200ms JS task is running, the response is delayed by the remaining task time. Identify long tasks with the Chrome DevTools Performance panel — "Long Tasks" are highlighted in red. Fix them by:

  • Breaking up long synchronous loops with setTimeout or the Scheduler API (scheduler.yield()) to yield control back to the browser between chunks
  • Moving heavy computation (data processing, sorting, parsing) to Web Workers, which run on a separate thread
  • Code-splitting — defer loading JS modules that aren't needed until a specific interaction occurs

Oversized event handlers. Click and input handlers that execute too much synchronous work add directly to INP. The pattern is to minimise synchronous work in the handler itself — update the UI optimistically, defer the expensive part with requestAnimationFrame or setTimeout(0).

Third-party scripts. Tag managers, chat widgets, A/B testing libraries, and analytics scripts can add 100–500ms of main-thread blocking. The Page Speed Inspector counts and lists third-party scripts per page — that list is the starting point for an INP investigation. Audit whether each third-party script is necessary and load non-critical ones with defer or after a user interaction.

INP tip: Chrome DevTools' "Interactions" track in the Performance panel shows the full breakdown of each interaction — input delay, processing time, and presentation delay. "Processing time" is where long tasks live; "input delay" points to too many event listeners registered at once.

Fixing CLS

CLS (Cumulative Layout Shift) measures unexpected visual movement during the page's life. A score over 0.1 usually traces to one of three causes — and once you identify which, the fix is straightforward.

Images without width and height attributes. When the browser doesn't know an image's dimensions before it loads, it reserves no space in the layout. The page shifts when the image arrives and the browser has to reflow. Fix:

<!-- Causes layout shift: no dimensions -->
<img src="hero.jpg" alt="Hero">

<!-- Prevents layout shift: dimensions set -->
<img src="hero.jpg" alt="Hero" width="1200" height="600">

The browser uses the width/height attributes to compute the correct aspect-ratio box before the image loads, reserving the right amount of space. You can also achieve this with CSS aspect-ratio, but HTML attributes are simpler and don't require JavaScript. The Page Speed Inspector flags images missing width and height under its recommendations.

Web fonts causing FOUT. Flash of Unstyled Text occurs when the browser renders text in a fallback font, then swaps to the custom font after it loads — causing text to reflow and shift other elements. Fix with font-display: swap on your @font-face declarations, combined with a size-adjust override to minimise the metric difference between the fallback and the custom font:

@font-face {
  font-family: 'MyFont';
  src: url('/fonts/myfont.woff2') format('woff2');
  font-display: swap;
  /* Adjust fallback metrics to reduce the swap shift */
  size-adjust: 105%;
  ascent-override: 90%;
}

For non-critical decorative fonts, font-display: optional avoids the shift entirely by only using the custom font if it loads within a short window — falling back permanently if not.

Dynamically injected content. Ads, cookie banners, newsletter pop-ins, and GDPR notices inserted above existing content push the rest of the page down, scoring directly as CLS. Reserve the space before injection:

  • For ads: always set an explicit min-height on the ad container matching the ad slot size
  • For banners: use a fixed height container and position the banner inside it from the start
  • For cookie notices: use position: fixed rather than inserting into the document flow

Field Data vs Lab Data

Lighthouse is lab data: it runs on a controlled machine under simulated network conditions with an empty cache. CrUX (Chrome User Experience Report) is field data: it aggregates real user visits over a 28-day rolling window from Chrome users who opted in to sharing performance data.

Google's ranking signal uses field data. A Lighthouse score of 95 doesn't guarantee passing Core Web Vitals if real users are on slower devices or connections. Common reasons lab and field data diverge:

  • Real users are on mid-range Android devices, not a high-end Mac
  • Real users have warm caches — some Lighthouse runs use empty cache
  • Third-party scripts behave differently in Lighthouse's isolated environment vs live
  • Dynamic content (personalisation, ads) is often absent in Lighthouse but present for real users

Use Google Search Console's Core Web Vitals report to see field data. The report shows which specific URLs fail, which metric they fail on, and the volume of affected sessions — prioritise fixing pages with the highest traffic first.

Diagnosing Which Pages Fail

Google Search Console groups failing URLs by issue type (LCP, INP, CLS) and shows which URLs are affected along with the number of poor sessions. This is the right starting point — it uses real-user data rather than lab estimates.

Once you have the failing URL list, use the Page Speed Inspector to measure each page individually. It reports:

  • TTFB — the first and most impactful LCP fix lever
  • Render-blocking scripts and stylesheets — direct LCP contributors
  • Images without width/height — the primary CLS cause
  • Images missing lazy loading — bandwidth that delays LCP
  • Third-party script count — the leading INP cause
  • DOM node count — excessive DOM size correlates with slow INP

Run the inspector against the specific URLs Google Search Console flags rather than your homepage — the failures are often concentrated on category pages, product pages, or article templates, not the homepage which usually gets the most optimisation attention.

Identify CWV Failure Causes in Seconds

Free, no signup. The Page Speed Inspector measures TTFB, detects render-blocking resources, identifies images without dimensions, and counts third-party scripts — the specific signals that drive Core Web Vitals failures.

Try the Page Speed Inspector Free →
SP

Sunny Pal Singh

Fellow · Technical Director — AI Infrastructure, Cloud Orchestration & Network Automation

Sunny is a Fellow and Technical Director specialising in AI infrastructure, cloud orchestration, and network automation. With hands-on depth across AWS, Azure, GCP, Red Hat OpenStack, and OpenShift, he leads high-performing teams of architects and engineers building transformative solutions at scale. He built ByteWaveNetwork to bring the same engineering rigour to everyday web tooling.

· ByteWaveNetwork

Affiliate disclosure: Some links on this page may be affiliate links. We only mention tools we've personally used and have an honest opinion about. Affiliate revenue helps keep ByteWaveNetwork's tools free and maintained. We are not paid by any of the tools compared in this article for favorable coverage.

Choose design