A fast site keeps visitors and helps search rankings. Core Web Vitals turn "fast" into three numbers you can measure and fix, and this checklist goes through them in order of impact.
Google ranks sites partly by Core Web Vitals — Largest Contentful Paint (LCP), Interaction to Next Paint (INP) and Cumulative Layout Shift (CLS). Measure real-user data first, then fix the biggest wins: right-sized modern images, a fast server response (page cache plus OPcache), less and later JavaScript, and reserved space for images and embeds. This guide covers measuring on your Domain India-hosted site and the fixes that matter most.
The three Core Web Vitals (2026)
| Metric | Good | Needs improvement | Poor | What it means |
|---|---|---|---|---|
| LCP | ≤2.5s | 2.5–4.0s | >4.0s | Time until largest visible element renders |
| INP | ≤200ms | 200–500ms | >500ms | Responsiveness to user interactions |
| CLS | ≤0.1 | 0.1–0.25 | >0.25 | Layout jumps during load |
75th percentile of real users over 28 days is what Google uses. "Works on my fast laptop" ≠ "good CWV".
Measure first
Tools
- PageSpeed Insights — enter URL, get lab + field data (pagespeed.web.dev)
- Chrome DevTools Lighthouse — local tests, simulated throttling
- Google Search Console — Core Web Vitals report (real users, aggregated)
- WebPageTest — deep filmstrip, waterfall, comparison
Run PageSpeed Insights on 5-10 key pages; log scores. Re-measure after each optimisation.
Real User Monitoring (RUM)
Lab data is misleading. Install RUM to see real user experience:
<script type="module">
import { onLCP, onINP, onCLS } from 'https://unpkg.com/web-vitals@5?module';
function sendToAnalytics({ name, value, id, rating }) {
// Your own endpoint, or forward to Google Analytics 4
const body = JSON.stringify({ name, value, id, rating, url: location.href });
// sendBeacon survives the page being closed; fall back to fetch
(navigator.sendBeacon && navigator.sendBeacon('/api/vitals', body)) ||
fetch('/api/vitals', { body, method: 'POST', keepalive: true });
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
</script>Or use a free service such as Cloudflare Web Analytics, which reports Core Web Vitals from real visitors.
Fix LCP (Largest Contentful Paint)
LCP element is usually a hero image or above-the-fold text block.
Fix 1 — Image optimisation
- Use modern formats: WebP / AVIF (30-50% smaller than JPEG)
- Serve correctly-sized images (don't serve 4000px to a 400px viewport)
- Use
srcsetfor responsive:
<img src="hero.webp"
srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1600.webp 1600w"
sizes="(max-width: 600px) 400px, 800px"
width="800" height="600"
fetchpriority="high"
alt="Hero">fetchpriority="high"on LCP image — tells browser to prioritise
On Domain India hosting:
- Shared hosting runs Apache, not LiteSpeed, so LiteSpeed Cache image features don't apply. Generate WebP with a plugin such as ShortPixel or EWWW Image Optimizer, or convert images before you upload them
- Cloudflare's Polish (on paid Cloudflare plans) converts image formats automatically
- Or use an image CDN such as Cloudinary or Imgix, or run imgproxy on your own VPS
Fix 2 — Preload critical resources
<link rel="preload" href="https://yourdomain.com/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="https://yourdomain.com/css/critical.css" as="style">
<link rel="preload" href="https://yourdomain.com/hero.webp" as="image">Fix 3 — Server response time (TTFB)
Target: TTFB < 800ms. Slow server = everything slow.
- PHP: make sure OPcache is on (see our OPcache article) and use a page cache (for WordPress, WP Super Cache or W3 Total Cache)
- Node.js: use clustering or worker threads
- Full-page cache at Cloudflare for pages that are the same for every visitor
- Move to a VPS if your plan's CPU limit is reached regularly (see My website is slow)
Fix 4 — Critical CSS inline
Inline above-the-fold CSS, defer the rest:
<style>
/* 5-10 KB of critical CSS for first paint */
body { font: 16px Inter; margin: 0; }
.hero { background: #0f172a; color: white; padding: 40px; }
...
</style>
<link rel="preload" href="https://yourdomain.com/css/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">Tools: critical npm package, Penthouse, or PurgeCSS.
Fix INP (Interaction to Next Paint)
INP replaced First Input Delay (FID) in March 2024. It measures how quickly the page responds to clicks, taps and key presses, reporting close to the slowest interaction on the page.
Fix 1 — Less JavaScript
Most INP issues come from JS blocking the main thread. Audit bundles:
# Next.js: add the @next/bundle-analyzer plugin to next.config, then
ANALYZE=true npm run build
# Vite:
npx vite-bundle-visualizerRemove unused libraries. Use import() for code-splitting non-critical routes.
Fix 2 — Defer third-party scripts
Analytics, chat widgets, social share buttons — defer:
<script src="https://third-party.com/widget.js" defer></script>
<!-- or load after interaction: -->
<script>
setTimeout(() => {
const s = document.createElement('script');
s.src = 'https://third-party.com/widget.js';
document.body.appendChild(s);
}, 3000);
</script>Fix 3 — Break up long tasks
Long tasks (>50ms) block interactions. Use scheduler.yield() where the browser supports it, or setTimeout as a fallback, to yield:
function yieldToMain() {
if (globalThis.scheduler?.yield) return scheduler.yield();
return new Promise(resolve => setTimeout(resolve, 0));
}
async function processBigList(items) {
for (let i = 0; i < items.length; i++) {
processItem(items[i]);
if (i % 50 === 0) await yieldToMain();
}
}Fix 4 — Debounce input handlers
let timer;
input.addEventListener('input', (e) => {
clearTimeout(timer);
timer = setTimeout(() => search(e.target.value), 200);
});Fix CLS (Cumulative Layout Shift)
Content jumping around = bad CLS.
Fix 1 — Always set width/height on images
<!-- BAD -->
<img src="pic.jpg">
<!-- GOOD -->
<img src="pic.jpg" width="800" height="600" alt="">Browser reserves space before image loads. No jump.
Fix 2 — Reserve space for ads / embeds
<div style="min-height: 250px; background: #f5f5f5;" id="ad-slot"></div>Fix 3 — Font loading — avoid FOIT/FOUT
@font-face {
font-family: 'Inter';
src: url('/fonts/inter.woff2') format('woff2');
font-display: swap; /* show fallback, swap when loaded */
}Use size-matched fallbacks to avoid CLS:
body {
font-family: 'Inter', 'Adjusted Arial', sans-serif;
/* 'Adjusted Arial' defined via @font-face with ascent/descent overrides to match Inter metrics */
}Fix 4 — Don't inject content above existing content
Adding a cookie banner on top, pushing page down = CLS. Use position: fixed for banners.
Quick wins for most Domain India sites
- Minify CSS and JS in your build step or with your CMS plugin (Cloudflare's Auto Minify has been retired)
- Put the site behind Cloudflare if you want an edge cache, and add a cache rule for pages that are the same for every visitor
- Convert hero images to WebP or AVIF and set explicit width and height
- Add
loading="lazy"to below-the-fold images (never to the LCP image) - Defer all JS except the critical path
- Preload the hero image and key fonts
- Inline critical CSS (the first 5–10 KB)
- Use the newest PHP version your site supports; newer versions are generally faster (check the versions offered in your control panel)
- Use a page cache plugin for WordPress and keep OPcache on
- Consider a VPS if your server response time stays high after caching
Server-level tweaks
On Domain India shared hosting, compression is already on: nginx gzips HTML, CSS, JS, JSON, XML and SVG on cPanel, and DirectAdmin has mod_deflate on server-wide. Brotli is not offered, and you don't need to add anything. The nginx block below is for your own VPS; the mod_expires block works in .htaccess on cPanel and DirectAdmin.
nginx (your own VPS)
# gzip (+ brotli if you build nginx with it)
gzip on;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/javascript application/json image/svg+xml;
# brotli (if ngx_brotli installed)
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;
# Cache static assets
location ~* \.(jpg|jpeg|png|gif|webp|avif|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}Apache/.htaccess
Only use a one-year expiry for files whose names change when their content changes (for example main.3f9a1c.css); otherwise visitors keep old versions.
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/webp "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
</IfModule>Running this on Domain India
- cPanel: nginx sits in front of Apache as a caching proxy and compresses text files; OPcache is on for websites. PHP versions up to 8.5 are offered (default 8.3), and GD supports WebP. A cached page can be served for up to 120 minutes, so add
?t=with a new value to the URL when you test a change. - DirectAdmin: compression (mod_deflate) is on server-wide and PHP versions up to 8.3 are offered. OPcache is not available on PHP 8.3 there, so check which versions have it in your panel.
- Webuzo: PHP 8.0 and 8.1 only; check that your CMS and plugins support them.
- VPS: self-managed with full root access, so the nginx settings above, Brotli and your own caching layers are up to you.
Common pitfalls
FAQ
How important are Core Web Vitals for SEO?
They are one of many ranking signals. Good content still matters most, but slow pages lose both rankings and visitors. Aim for "Good" on all three metrics at the 75th percentile.
How do I speed up WordPress on Domain India shared hosting?
Use a page cache plugin such as WP Super Cache or W3 Total Cache (shared hosting runs Apache, so LiteSpeed Cache does not apply), compress and resize images, lazy-load media below the fold and remove plugins you don't need. See the My website is slow guide for more.
Which tool should I use for continuous monitoring?
Lighthouse CI in GitHub Actions is free and can fail a pull request when scores drop. Paid services such as Calibre and SpeedCurve add dashboards and alerts. Combine either with real-user data from Search Console or your own RUM script.
Does Cloudflare improve Core Web Vitals?
It can. Cloudflare's CDN serves static files from nearby locations, and a cache rule for HTML can cut server response time. The gain depends on your site, so measure before and after.
Is an image CDN worth it?
For image-heavy sites such as shops, portfolios and photo blogs, often yes. For text-heavy sites, correctly sized WebP images and ordinary caching are usually enough.
Ready to speed up your site? Start with My website is slow, check the PHP OPcache guide, and host with cPanel hosting or a VPS when you need full control.
Domain India cPanel hosting includes an nginx caching proxy, compression and OPcache, so you can focus on images and JavaScript.
View cPanel hosting