Core Web Vitals Explained: What Actually Affects Your Score

LCP, INP, and CLS explained in plain terms, with the specific, common causes of a bad score and how to fix each one.

DevFieldGuideJuly 11, 2026 (updated July 23, 2026)6 min read
Share:

Core Web Vitals are the three metrics Google uses to measure real-world user experience — and unlike older performance metrics, they measure what users actually perceive, not just raw load time.

LCP — Largest Contentful Paint

Measures how long it takes for the largest visible element (usually a hero image, a heading, or a large block of text) to render. This is meant to approximate "when does the page feel loaded" better than older metrics like "time to first byte," which can be fast even when the page is still visually blank.

Common causes of bad LCP:

  • A large hero image that isn't optimized (wrong format, no compression, no responsive sizing).
  • Render-blocking CSS/JS that delays the browser from painting anything.
  • Slow server response time (the page can't start rendering until the HTML arrives).

Fixes:

html
<img src="/hero.jpg" fetchpriority="high" alt="..." />

Marking your LCP image with fetchpriority="high" tells the browser to fetch it before other, lower-priority resources. Combined with serving modern formats (WebP/AVIF) and proper srcset sizing, this is usually the highest-leverage LCP fix.

INP — Interaction to Next Paint

Replaced the older "First Input Delay" metric. INP measures the latency of all interactions throughout a page's lifetime (clicks, taps, key presses), not just the first one — capturing responsiveness across the whole visit, not a single early moment.

Common causes of bad INP:

  • Long JavaScript tasks blocking the main thread when a user interacts (a heavy click handler, an expensive re-render).
  • Large, unoptimized React re-renders triggered by a single state change.

Fixes: Break up long tasks (setTimeout or scheduler.yield() to yield back to the browser between chunks of work), memoize expensive computations, and avoid triggering large component tree re-renders from a single small interaction.

CLS — Cumulative Layout Shift

Measures unexpected layout movement — content jumping around as a page loads, most commonly from images or ads loading without reserved space, or fonts swapping in and reflowing text.

Common causes:

  • <img> tags without explicit width/height (or aspect-ratio), so the browser doesn't know how much space to reserve before the image loads.
  • Ads or embeds injected without a reserved slot.
  • Web fonts that swap in with different metrics than the fallback font, shifting text.

Fixes:

html
<img src="/photo.jpg" width="800" height="450" alt="..." />

Always specify dimensions (or aspect-ratio in CSS) so the browser reserves space immediately, before the image loads — this is precisely why this project's AdSlot component (src/components/ads/ad-slot.tsx) reserves a fixed size up front rather than sizing to content.

AspectLab data (Lighthouse)Field data (PageSpeed Insights / CrUX)
SourceA single simulated run, fixed conditionsReal visitors, real devices, real networks
Best forDebugging one specific page loadWhat Google actually uses for the ranking signal
Percentile usedN/A — one run75th percentile across real visits

Where to actually check your scores

PageSpeed Insights and the Chrome DevTools Lighthouse panel both report all three metrics, and — importantly — PageSpeed Insights shows real field data from Chrome users when available (the "Field Data" section), which reflects your actual visitors' experience, not just a single lab-simulated run. Lab data (Lighthouse) is useful for debugging a specific page load; field data is what Google actually uses for the ranking signal.

The practical priority order

LCP and CLS are usually the easiest wins (image dimensions, image optimization, avoiding render-blocking resources) and often the biggest score movers. INP tends to require more invasive JavaScript profiling and is worth tackling once the more mechanical LCP/CLS fixes are in place.

The 75th percentile threshold — why "mostly good" isn't good enough

Google doesn't score Core Web Vitals on your average visitor's experience — it uses the 75th percentile across real visits, meaning a page only passes if at least 75% of real visits meet the "good" threshold for a given metric. This is a meaningfully stricter bar than it first sounds: a page that's fast for most users but has a long tail of slow experiences (a subset on poor mobile connections, older devices, or a specific unoptimized page template) can fail the field-data assessment even though the median experience is genuinely good. This is exactly why fixing the worst-case paths (a slow-loading image on a specific template, a heavy third-party script only present on certain pages) often matters more for passing Core Web Vitals than optimizing an already-fast median case further.

Third-party scripts: a common, easy-to-miss INP and LCP cost

Analytics tags, chat widgets, and ad scripts are a frequent, underestimated source of both poor INP (they parse and execute JavaScript on the main thread, competing with your own code for the same thread) and poor LCP (a synchronously-loaded third-party script can delay the browser from even starting to render your actual content). Loading third-party scripts with async or defer, and specifically avoiding synchronous <script> tags in the <head> for anything non-essential to the initial render, is often a bigger win than people expect relative to the effort — a single blocking analytics tag can meaningfully move both metrics on its own.

Two of the mechanisms behind these metrics are worth understanding on their own: modern layout techniques from responsive design directly affect CLS, and INP is fundamentally about not blocking the JavaScript event loop with long-running work when a user interacts.

Common mistakes

Common mistakes
  • Optimizing based on a single Lighthouse run instead of real field data. Lab tests run under fixed, often-throttled conditions and can both overstate and understate what real visitors experience — treat a single Lighthouse score as a debugging tool, not a final verdict.
  • Marking every image fetchpriority="high". If everything is high priority, nothing effectively is — reserve it specifically for the actual LCP element, and let everything else load at normal priority.
  • Fixing CLS by adding width/height to images but forgetting ad slots and embeds, which are just as common a CLS source and need the same fixed-space treatment before they load.
  • Chasing a perfect Lighthouse score on a page with genuinely weak content. Core Web Vitals are one ranking signal among many, and a technically flawless but thin page still loses to a well-written, reasonably-fast one — performance work has a ceiling on how much it can compensate for content quality.
Advertisement

Frequently Asked Questions

Advertisement
DevFieldGuide
DevFieldGuide

Editorial Team

Practical tutorials and developer tools, written and maintained by the DevFieldGuide team.

Enjoyed this article?

Get the next one straight to your inbox, along with the best of what we publish each week.

Related Articles

More in Web Development

View all