Core Web Vitals: Measure and Improve Web Performance
You've built a fast website, but users still complain about slowness, and your search rankings aren't where you want them. The problem? You're not measuring the right things. Core Web Vitals (CWV) are Google's metrics for real-world user experience: Largest Contentful Paint (LCP), Interaction to Next Paint (INP), and Cumulative Layout Shift (CLS). If you ignore them, you're leaving performance—and SEO—on the table.
This guide shows you how to measure CWV accurately and fix the most common issues. No fluff, just actionable steps.
What Are Core Web Vitals?
Core Web Vitals are three specific metrics that quantify how users perceive loading, interactivity, and visual stability:
- LCP measures loading performance. It marks when the largest content element (image, video, text block) becomes visible. Aim for ≤ 2.5 seconds.
- INP measures responsiveness. It records the latency of all interactions (clicks, taps, key presses) and reports a high-percentile value. Aim for ≤ 200 milliseconds.
- CLS measures visual stability. It calculates unexpected layout shifts. Aim for ≤ 0.1.
These thresholds are based on real-user data from the Chrome User Experience Report (CrUX). Meeting them improves user satisfaction and can boost search rankings.
How to Measure Core Web Vitals
You need both lab and field data. Lab tools simulate conditions; field data reflects real users.
Lab Tools
- Lighthouse (in Chrome DevTools or CI) gives a snapshot with diagnostics.
- PageSpeed Insights combines lab and field data for a URL.
- Web Vitals Extension logs CWV in the Chrome console as you browse.
Field Tools
- Chrome UX Report (CrUX) shows aggregated real-user data for millions of sites.
- web-vitals JavaScript library lets you collect CWV from your own users and send to analytics.
- Search Console reports CWV status for your site based on CrUX.
Start with field data to identify problem pages, then use lab tools to debug.
Improving LCP
LCP is often the easiest to improve with a few targeted fixes.
- Optimize images. Use modern formats (WebP, AVIF), compress without visible quality loss, and set explicit width/height. Tools like Image Compressor can help reduce file size.
- Preload the LCP image. Add
<link rel="preload" as="image" href="#">in the head. - Eliminate render-blocking resources. Inline critical CSS, defer non-critical CSS/JS, and avoid synchronous scripts in the head.
- Use a CDN. Serve assets from a location near the user to reduce latency.
- Enable text compression. Brotli or gzip for HTML, CSS, JS.
Example of preloading an LCP image:
<link rel="preload" as="image" href="/images/hero.avif" type="image/avif">
Improving INP
INP measures how quickly your page responds to user input. Long tasks block the main thread and delay interactions.
- Break up long tasks. Use
setTimeoutorrequestIdleCallbackto yield to the main thread. - Optimize event handlers. Debounce or throttle high-frequency events like scroll and resize.
- Reduce JavaScript. Code-split, tree-shake, and lazy-load non-critical scripts.
- Use web workers for heavy computations.
- Avoid large DOM sizes. Keep the DOM under 1500 nodes if possible.
Example of yielding to the main thread:
async function yieldToMain() {
if ('scheduler' in window && 'yield' in scheduler) {
await scheduler.yield();
} else {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
Improving CLS
Layout shifts happen when elements change position unexpectedly. Common causes: images without dimensions, ads, embeds, and dynamically injected content.
- Always set width and height on images and videos. This lets the browser reserve space.
- Reserve space for ads and embeds. Use CSS aspect-ratio or fixed containers.
- Avoid inserting content above existing content unless triggered by user interaction.
- Use
font-display: swapand preload fonts to avoid invisible text shifts. - Be careful with animations. Use transform and opacity instead of properties that trigger layout.
Monitoring and Continuous Improvement
Performance is not a one-time fix. Set up monitoring to catch regressions.
- Use the
web-vitalslibrary to send CWV to your analytics:
import {onLCP, onINP, onCLS} from 'web-vitals';
function sendToAnalytics(metric) {
const body = JSON.stringify(metric);
navigator.sendBeacon('/analytics', body);
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
- Set up alerts for when metrics exceed thresholds.
- Run Lighthouse in CI for every pull request.
- Review CrUX data monthly to track trends.
Comparison of Core Web Vitals
| Metric | What it measures | Good threshold | Common fixes |
|---|---|---|---|
| LCP | Loading performance | ≤ 2.5s | Optimize images, preload, CDN |
| INP | Responsiveness | ≤ 200ms | Break long tasks, reduce JS |
| CLS | Visual stability | ≤ 0.1 | Set dimensions, reserve space |
FAQ
What are the current thresholds for Core Web Vitals?
LCP: good ≤ 2.5s, needs improvement ≤ 4.0s, poor > 4.0s. INP: good ≤ 200ms, needs improvement ≤ 500ms, poor > 500ms. CLS: good ≤ 0.1, needs improvement ≤ 0.25, poor > 0.25.
How often should I check Core Web Vitals?
Monitor field data continuously via analytics. Review CrUX and Search Console monthly. Run lab tests (Lighthouse) on every significant code change.
Can I improve Core Web Vitals without a developer?
Some fixes like compressing images or enabling caching can be done via plugins or hosting settings. But deeper optimizations (code splitting, reducing JS) usually require developer involvement.
Ready to optimize your images for better LCP? Try our free Image Compressor to reduce file sizes without losing quality.