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:
<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 explicitwidth/height(oraspect-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:
<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.
| Aspect | Lab data (Lighthouse) | Field data (PageSpeed Insights / CrUX) |
|---|---|---|
| Source | A single simulated run, fixed conditions | Real visitors, real devices, real networks |
| Best for | Debugging one specific page load | What Google actually uses for the ranking signal |
| Percentile used | N/A — one run | 75th 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
- 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/heightto 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.
Related reading
- A Practical Guide to Responsive Design in 2026 — shares tags: web-development, programming (same category).
- The JavaScript Event Loop, Explained With Diagrams — shares tags: programming, web-development.
- OWASP Top 10, Explained for Developers Who Aren't Security Specialists — shares tags: web-development, programming.
- Async Python with asyncio: A Practical Introduction — shares tags: programming.
- Big O Notation Without the Math Panic — shares tags: programming.