Google Core Web Vitals and Performance Checklist
Optimize Google Core Web Vitals for loading speed, interactivity, and visual stability across all devices. INP replaced FID in March 2024 making this the most important Core Web Vitals SEO focus area. These 12 checks cover every layer from server to browser.
What Core Web Vitals Measure
Core Web Vitals are Google's three metrics that quantify the real-world user experience of a web page. They are confirmed ranking signals and directly impact user engagement, conversion rates, and bounce rates.
In 2026, CWV also affects AI search visibility. AI agents that render pages for screenshots or parse HTML expect fast, stable content. Poor CWV correlates with poor user experience across all surfaces including AI-generated answers.
Each metric measures a different aspect of the loading experience:
Sources
- Sites meeting Core Web Vitals thresholds are 24% less likely to be abandoned, Google News Initiative CWV training.
- INP replaced FID as a Core Web Vital in March 2024, Google Search Central.
CWV Metrics Comparison
The 12 Performance Checks
Grouped by metric and ranked by impact. Fix in priority order.
| # | Check | Metric | Impact | Difficulty |
|---|---|---|---|---|
| 1 | Optimize LCP element (preload, eliminate blockers) | LCP | Critical | Medium |
| 2 | Eliminate render-blocking resources | LCP | Critical | Medium |
| 3 | Optimize images (next-gen formats, responsive) | LCP | Critical | Easy |
| 4 | Reduce server response time (TTFB) | LCP | High | Hard |
| 5 | Break up long JavaScript tasks | INP | Critical | Medium |
| 6 | Defer and audit third-party scripts | INP | High | Medium |
| 7 | Debounce and throttle event handlers | INP | Medium | Easy |
| 8 | Set explicit dimensions on all media | CLS | Critical | Easy |
| 9 | Reserve space for ads and embeds | CLS | High | Medium |
| 10 | Use font-display: swap for web fonts | CLS | High | Easy |
| 11 | Enable CDN and caching strategy | All | High | Medium |
| 12 | Set a performance budget and monitor CrUX | All | Medium | Hard |
INP Replaced FID: What Changed
Google replaced First Input Delay (FID) with Interaction to Next Paint (INP) in March 2024. Here is what that means for Core Web Vitals SEO.
FID measured the time from when a user first interacted with a page to when the browser could begin processing the event handler. It only captured the first interaction and was a poor proxy for overall interactivity. A page could have excellent FID but terrible responsiveness on subsequent taps or clicks.
INP measures the latency of all interactions throughout the page lifecycle and reports the worst (or near-worst) interaction. This gives a much more accurate picture of real-world responsiveness. INP is a more rigorous metric that catches issues FID missed: slow event handlers, long tasks from third-party scripts, and main thread congestion during the full user session.
Key changes for SEO:
- INP threshold: good under 200ms, poor over 500ms (vs FID 100ms/300ms)
- INP considers all interactions, not just the first one
- Pages that passed FID may fail INP if they have any slow interactions
- INP is a confirmed ranking signal in the Core Web Vitals assessment
Core web vitals news: Since the INP rollout, approximately 30-40% of sites that previously passed FID now need optimization work to pass INP. This makes INP optimization the most important CWV focus area for 2025-2026.
FID vs INP Comparison
Rendering Architecture and CWV
How your rendering strategy affects Core Web Vitals and SEO performance.
Your choice of rendering architecture directly determines your CWV baseline. Different architectures trade off initial load speed against interactivity and scalability. Understanding which one you use (and whether you should switch) is a foundational performance decision.
| Architecture | LCP | INP | CLS | SEO | Best For |
|---|---|---|---|---|---|
| SSR (Server-Side Rendering) | Good | Fair | Good | Excellent | Content sites, SEO-critical pages |
| SSG (Static Site Generation) | Excellent | Excellent | Excellent | Excellent | Blogs, docs, marketing pages |
| ISR (Incremental Static Regeneration) | Excellent | Good | Good | Excellent | Large content sites with frequent updates |
| CSR (Client-Side Rendering) | Poor | Poor | Fair | Poor | Web apps, dashboards (with SSR fallback) |
| DPR (Distributed Persistent Rendering) | Excellent | Excellent | Excellent | Excellent | Edge-rendered dynamic content |
Architecture Impact Summary
Migrating from CSR to SSR or SSG typically improves LCP by 40-60% and INP by 30-50%. If your site is CSR-only, add SSR for critical pages using frameworks like Next.js, Nuxt, or Astro.
Deep Dive: Every Check Explained
Implementation guides with code examples for all 12 checks.
1 Optimize Largest Contentful Paint (LCP)
Target: under 2.5 seconds. Identify the LCP element using Lighthouse or Chrome DevTools. It is usually a hero image, large heading, or video poster. Preload the LCP resource and eliminate any render-blocking scripts or stylesheets above the fold.
<!-- Preload the LCP image with high priority --> <link rel="preload" as="image" href="/images/hero.webp" fetchpriority="high"> <!-- Preload critical CSS --> <link rel="preload" as="style" href="/css/critical.css" onload="this.onload=null;this.rel='stylesheet'"> <!-- Defer non-critical JavaScript --> <script defer src="/js/main.js"></script>
Monitor LCP in the field using the CrUX report in Google Search Console. Lab tools (Lighthouse) show potential issues; field data shows real user impact.
2 Eliminate Render-Blocking Resources
Render-blocking resources delay the browser from painting anything on screen. Inline critical CSS in the head and defer all non-critical CSS and JS. This is the single highest-impact fix for LCP on most sites.
<!-- Inline critical CSS directly in the HTML head -->
<style>
/* Critical above-the-fold styles */
body { font-family: sans-serif; margin: 0; }
.hero { display: flex; ... }
</style>
<!-- Load non-critical CSS asynchronously -->
<link rel="preload" as="style" href="/css/full.css"
onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/css/full.css"></noscript> 3 Optimize Images
Images account for 50-70% of page weight on most sites. Use next-gen formats (WebP, AVIF), serve responsive sizes with srcset, lazy load below-the-fold images, and compress aggressively without visible quality loss.
<picture>
<source srcset="/image.avif" type="image/avif">
<source srcset="/image.webp" type="image/webp">
<img src="/image.jpg"
srcset="/image-400.jpg 400w,
/image-800.jpg 800w,
/image-1200.jpg 1200w"
sizes="(max-width: 600px) 100vw, 800px"
width="800" height="450"
loading="lazy"
decoding="async"
alt="Description">
</picture>
# Bulk convert to WebP with cwebp
for img in *.jpg; do
cwebp -q 80 "$img" -o "${img%.jpg}.webp"
done
# Convert to AVIF with avifenc
for img in *.jpg; do
avifenc --speed 6 --min 20 --max 40 "$img" "${img%.jpg}.avif"
done 4 Reduce Server Response Time (TTFB)
Target: under 200ms. Slow TTFB indicates server-side bottlenecks. Upgrade hosting, enable PHP OPcache, optimize database queries, implement server-side page caching, and use a reverse proxy like Nginx or Varnish.
# Test TTFB from multiple locations
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s\n" \
https://www.yourdomain.com
# PHP OPcache configuration
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
# Nginx fastcgi cache
fastcgi_cache_path /tmp/nginx_cache levels=1:2 keys_zone=mycache:10m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout updating; 5 Break Up Long JavaScript Tasks
Target INP: under 200ms. Long tasks (over 50ms) block the main thread and make the page feel unresponsive. Break them up by yielding to the main thread, using async/await, and splitting work into smaller chunks.
New in 2025-2026: The scheduler.yield() API provides a dedicated mechanism for yielding control back to the browser without the overhead of setTimeout(0). Unlike setTimeout, scheduler.yield() integrates with the browser's task prioritization system and does not require a minimum delay. It is supported in Chrome 115+ and is the preferred way to break up long tasks.
// Modern approach: scheduler.yield() (Chrome 115+)
async function processItems(items) {
for (const item of items) {
heavyProcess(item);
await scheduler.yield(); // yield without timeout overhead
}
}
// Fallback: yield via setTimeout
async function processItemsWithFallback(items) {
for (const item of items) {
heavyProcess(item);
if ('scheduler' in window && 'yield' in scheduler) {
await scheduler.yield();
} else {
await new Promise(r => setTimeout(r, 0));
}
}
}
// Use requestIdleCallback for non-critical work
function scheduleWork(task) {
if ('requestIdleCallback' in window) {
requestIdleCallback(task, { timeout: 2000 });
} else {
setTimeout(task, 1);
}
}
// Avoid forced reflows
// Bad: Reading layout after writing
element.style.width = '100px';
const width = element.offsetWidth; // triggers forced reflow
// Good: Batch reads separately from writes
const reads = [];
// ... all writes first, then reads 6 Defer and Audit Third-Party Scripts
Third-party scripts (analytics, ads, social widgets, chatbots) are the #1 cause of poor INP. Each script competes for the main thread. Audit every third-party script, load them async, and remove any that are not essential.
<!-- Load third-party scripts with async or defer -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXX"></script>
<!-- Use IntersectionObserver to lazy load non-critical widgets -->
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const script = document.createElement('script');
script.src = entry.target.dataset.src;
document.body.appendChild(script);
observer.unobserve(entry.target);
}
});
});
document.querySelectorAll('[data-lazy-script]').forEach(el => observer.observe(el)); Use Chrome DevTools Performance tab to record page load and identify which scripts take the most main thread time. Remove any tag that does not provide clear business value.
7 Debounce and Throttle Event Handlers
Event handlers attached to scroll, resize, mousemove, or keydown fire hundreds of times per second. Without debouncing, each invocation runs on the main thread and degrades INP. Debounce delays execution until after a pause; throttle limits execution to once per interval.
// Debounce: waits for a pause before executing
function debounce(fn, delay = 150) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
window.addEventListener('resize', debounce(() => {
// handle resize
}, 150));
// Throttle: limits execution rate
function throttle(fn, limit = 100) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => { inThrottle = false; }, limit);
}
};
}
window.addEventListener('scroll', throttle(() => {
// handle scroll
}, 100)); 8 Set Explicit Dimensions on All Media
CLS is caused primarily by images, videos, iframes, and ads that load without reserved space. Always set explicit width and height attributes on all media elements. This allows the browser to reserve the correct space before the resource loads.
<!-- Always set explicit width and height -->
<img src="/image.webp" width="800" height="450" alt="" loading="lazy">
<!-- For responsive images with unknown aspect ratios, use aspect-ratio CSS -->
img, video, iframe {
max-width: 100%;
height: auto;
aspect-ratio: attr(width) / attr(height);
}
<!-- Reserve space for embeds with a wrapper -->
<div style="position: relative; padding-bottom: 56.25%; height: 0;">
<iframe src="https://www.youtube.com/embed/..."
style="position: absolute; top: 0; left: 0;
width: 100%; height: 100%;"></iframe>
</div> 9 Reserve Space for Ads and Embeds
Dynamic content like ads and embeds cause the most disruptive layout shifts because they load after the initial paint. Reserve the exact space they will occupy using min-height placeholders.
<!-- Reserve ad space with a placeholder -->
<div style="min-height: 250px; width: 100%; background: #f0f0f0;"
id="ad-slot-desktop">
<!-- Ad loads here -->
</div>
<!-- For multi-size ads, reserve the maximum possible space -->
<div class="ad-container" style="min-height: 90px;">
<div id="ad-slot-responsive"></div>
</div> 10 Use font-display: swap for Web Fonts
Custom web fonts cause CLS in two ways: FOIT (Flash of Invisible Text) where text is hidden until the font loads, and FOUT (Flash of Unstyled Text) where text swaps from fallback to custom font. Use font-display: swap to show text immediately with a fallback font.
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom-font.woff2') format('woff2');
font-display: swap;
font-weight: 400;
}
/* Preload the font for earlier discovery */
<link rel="preload" as="font" href="/fonts/custom-font.woff2"
type="font/woff2" crossorigin>
/* Use font-size-adjust to minimize layout shift during swap */
body {
font-family: 'CustomFont', Arial, sans-serif;
font-size-adjust: 0.5;
} 11 Enable CDN and Caching Strategy
A CDN serves content from servers closest to the user, reducing latency by 30-60%. Cloudflare, BunnyCDN, and AWS CloudFront offer generous free or low-cost tiers. Combine with proper Cache-Control headers and Brotli compression.
# Cache-Control headers for different asset types
# Images and fonts: cache for 1 year
location ~* \.(webp|avif|jpg|png|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# CSS and JS: cache for 1 month
location ~* \.(css|js)$ {
expires 1M;
add_header Cache-Control "public";
}
# HTML: short cache or no cache
location ~* \.html$ {
expires 0;
add_header Cache-Control "no-cache";
}
# Enable Brotli compression on CDN
brotli on;
brotli_comp_level 6;
brotli_types text/html text/css application/javascript
image/svg+xml application/json; 12 Set a Performance Budget and Monitor CrUX
A performance budget defines the maximum allowed size or time for each page. Track it in CI/CD to prevent regressions. Monitor Chrome User Experience Report (CrUX) data for real-user performance trends.
Understanding CrUX: The 75th Percentile
Google uses the 75th percentile of real-user measurements to determine whether a page passes Core Web Vitals. This means at least 75% of visits must meet the good threshold. If your LCP is 2.0s median but 30% of users experience 4.0s, you fail the LCP assessment. This is why lab tools (Lighthouse) alone are insufficient. Always validate against CrUX field data because real-user conditions vary widely by device, network, and geography.
Monitor CrUX in Google Search Console under the Core Web Vitals report. It shows the percentage of URLs rated Good, Need Improvement, and Poor for each metric. A sudden shift from Good to Poor often correlates with a recent deployment.
// Performance budget example (budget.json)
{
"resources": {
"total": { "maxSize": "500kB" },
"javascript": { "maxSize": "200kB" },
"css": { "maxSize": "50kB" },
"images": { "maxSize": "300kB" },
"fonts": { "maxSize": "50kB" }
},
"timings": {
"lcp": { "maxTime": 2500 },
"inp": { "maxTime": 200 },
"cls": { "maxScore": 0.1 },
"ttfb": { "maxTime": 200 }
}
}
# Use Lighthouse CI to enforce budgets
# npx lhci collect --no-lr
# npx lhci assert --budget-file budget.json
# npx lhci upload Lab vs Field Data: Lighthouse runs on a simulated device with a throttled connection. It catches obvious issues but cannot represent real-user conditions. CrUX aggregates data from millions of real Chrome users. Always prioritize field data for ranking decisions because Google uses field data (CrUX) for the CWV ranking signal. Use lab data for debugging specific issues, and field data for understanding real-world impact.
Common Performance Mistakes
Bad practices that wreck Core Web Vitals.
Bad Practice vs Best Practice
Performance Tools
Tools for measuring, monitoring, and debugging Core Web Vitals.
Google PageSpeed Insights
Lab and field data for any URL. Shows LCP, INP, CLS with improvement suggestions.
FreeCrUX Dashboard
Real-user performance data from Chrome users. Track CWV trends over time for your entire site.
FreeLighthouse CI
Automated performance testing in CI/CD pipelines. Enforce performance budgets on every deployment.
FreeWebPageTest
Detailed waterfall charts, filmstrip view, and multi-location testing for advanced debugging.
FreeChrome DevTools
Performance tab, Network tab, Coverage tab, and Lighthouse panel for in-browser debugging.
FreeRequest Metrics
Real user monitoring (RUM) with weekly reports and alerting for CWV regressions.
Paid (free tier)Related Checklists
Keep exploring the technical SEO series. Every checklist follows the same structure.
CDN, Caching, and Hosting
TTFB and cache hit rates set the floor for every performance metric.
Image SEO
The fastest and most common way to cut LCP and page weight.
JavaScript SEO and Rendering
How rendering pipelines delay LCP and INP.
Website Accessibility
Semantic HTML and keyboard support overlap with performance.
Technical On-Page SEO
Titles and metas are part of the same performance pass.
Crawl Budget and Log Analysis
How slow responses throttle crawl rate in your logs.
Need Technical SEO Help?
Get professional SEO audit services and technical SEO solutions from Clienvora. Our expert team delivers measurable results for businesses of all sizes.
Free consultation. Get a personalized technical SEO audit for your website today. Or download the full checklist PDF.
Frequently Asked Questions
Common questions about Core Web Vitals and site performance.
Core Web Vitals are Google's three metrics for measuring real-world user experience: Largest Contentful Paint (LCP for loading speed), Interaction to Next Paint (INP for interactivity), and Cumulative Layout Shift (CLS for visual stability). They are confirmed ranking signals.
Identify the LCP element using Lighthouse, preload it with fetchpriority=high, eliminate render-blocking resources, optimize images to WebP/AVIF, reduce TTFB under 200ms, and remove unnecessary third-party scripts.
Images and videos without explicit dimensions, dynamically injected content without reserved space, web fonts with FOIT, ads and embeds that resize after loading, and custom fonts that cause FOUT without proper font-display settings.
Break up long JavaScript tasks by yielding to the main thread, defer third-party scripts, debounce event handlers, avoid forced reflows, minimize DOM size, and use web workers for heavy computation.
Under 200ms. TTFB (Time to First Byte) measures how long the server takes to start responding. Poor TTFB is usually caused by slow hosting, unoptimized databases, missing cache layers, or slow application code.
Yes, INP (Interaction to Next Paint) replaced FID (First Input Delay) as a Core Web Vital in March 2024. INP measures all interactions throughout the page lifecycle, not just the first one. The good threshold is under 200ms (vs 100ms for FID). This was one of the biggest core web vitals news updates in recent years, affecting 30-40% of sites that previously passed FID.
Both. Lab data (Lighthouse) helps you debug specific issues. Field data (CrUX, RUM) shows real user experience. Always prioritize field data for ranking decisions because Google uses field data for the CWV ranking signal.
Check the CrUX report in Google Search Console weekly. Set up alerts for CWV regressions using tools like Request Metrics or DebugBear. Run Lighthouse after every significant deployment to catch regressions early.