Improving Core Web Vitals: The Practical Guide

LCP < 2.5s, INP < 200ms, CLS < 0.1 — three metrics that determine your Google ranking. We explain how to improve each.
What Are Core Web Vitals and Why Do They Matter?
In May 2021, Google began using Core Web Vitals as a ranking factor in search results. A faster site ranks higher. Not just for SEO reasons — but because better user experience means higher conversion rates.
Core Web Vitals consists of three primary metrics:
- LCP (Largest Contentful Paint) — time until the largest element on the page appears
- INP (Interaction to Next Paint) — site responsiveness to user interactions
- CLS (Cumulative Layout Shift) — how stable the page is during loading
Measuring Core Web Vitals
# Free measurement tools:
# 1. Google PageSpeed Insights: pagespeed.web.dev
# 2. Chrome DevTools → Lighthouse
# 3. Search Console → Core Web Vitals report
# 4. web-vitals npm package (real user measurements)
// Measure Core Web Vitals in your code
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(({ value, rating }) => {
console.log(`LCP: ${value}ms — ${rating}`);
gtag('event', 'web_vitals', {
event_category: 'Web Vitals',
event_label: 'LCP',
value: Math.round(value),
non_interaction: true,
});
});
onINP(({ value }) => console.log(`INP: ${value}ms`));
onCLS(({ value }) => console.log(`CLS: ${value}`));
Required Targets
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | < 2.5s | 2.5s - 4s | > 4s |
| INP | < 200ms | 200ms - 500ms | > 500ms |
| CLS | < 0.1 | 0.1 - 0.25 | > 0.25 |
Improving LCP (Largest Contentful Paint)
LCP measures when the largest visible element on the page appears — usually a hero image or main heading.
1. Optimize the Hero Image
<!-- Most common mistake -->
<img src="hero.jpg" loading="lazy" alt="hero">
<!-- Correct: hero image does not need lazy loading -->
<img
src="hero.webp"
fetchpriority="high"
loading="eager"
decoding="async"
width="1200"
height="600"
alt="hero"
>
<!-- Preload hero image in head -->
<link
rel="preload"
as="image"
href="https://cloud.net.sa/images/hero.webp"
imagesrcset="/images/hero-400.webp 400w, /images/hero-800.webp 800w"
imagesizes="100vw"
>
2. Reduce Time to First Byte (TTFB)
# nginx: enable HTTP/2
listen 443 ssl http2;
# Enable compression
gzip on;
gzip_comp_level 5;
gzip_types text/html text/css application/javascript application/json;
// Laravel: Cache static pages
// Reduces TTFB from 300ms to under 50ms
Route::get('/', function {
return Cache::remember('page:home', 3600, function {
return Inertia::render('Home', HomeController::getData);
});
});
3. Critical CSS
# Extract critical CSS for above-the-fold content
npm install -g critical
critical index.html --inline --minify > output.html
<!-- Inline critical CSS in head instead of loading it -->
<style>
/* Critical CSS here - content visible immediately */
.hero { ... }
.header { ... }
</style>
<!-- Remaining CSS loaded asynchronously -->
<link rel="preload" href="https://cloud.net.sa/css/app.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
Improving INP (Interaction to Next Paint)
INP measures how quickly the page responds when clicking or typing.
1. Avoid Main Thread Blocking
// Wrong: heavy calculation on Main Thread
button.addEventListener('click', => {
const result = heavyCalculation; // blocks UI
updateUI(result);
});
// Correct: move heavy work to Web Worker
const worker = new Worker('/workers/calculator.js');
button.addEventListener('click', => {
worker.postMessage({ type: 'calculate', data: inputData });
});
worker.onmessage = ({ data }) => updateUI(data.result);
2. Reduce JavaScript Bundle Size
# Analyze bundle size
npm run build -- --report
npx webpack-bundle-analyzer dist/stats.json
// Code splitting in React
const HeavyComponent = React.lazy( => import('./HeavyComponent'));
// Dynamic import
const { Chart } = await import('./chart-library');
3. Defer Non-Essential Code Execution
<!-- Load scripts asynchronously -->
<script src="analytics.js" defer></script>
<script src="chat-widget.js" defer></script>
<!-- Only critical scripts load synchronously -->
<script src="critical.js"></script>
Improving CLS (Cumulative Layout Shift)
CLS measures how much elements shift during page load.
1. Always Specify Image Dimensions
<!-- Wrong: image causes layout shift on load -->
<img src="product.jpg" alt="...">
<!-- Correct: specifying dimensions reserves space in advance -->
<img src="product.webp" width="800" height="600" alt="...">
<!-- Or using aspect-ratio in CSS -->
<style>
.product-image {
aspect-ratio: 4 / 3;
width: 100%;
}
</style>
2. Load Fonts Correctly
<!-- Preload primary fonts -->
<link rel="preload" href="https://cloud.net.sa/fonts/noto-kufi-arabic.woff2" as="font" type="font/woff2" crossorigin>
/* font-display: optional prevents CLS from fonts */
@font-face {
font-family: 'Noto Kufi Arabic';
src: url('/fonts/noto-kufi-arabic.woff2') format('woff2');
font-display: optional;
font-weight: 400;
}
3. Reserve Space for Dynamic Content
/* Reserve space for content that will load later */
.ad-container {
min-height: 250px;
width: 100%;
}
.skeleton-card {
height: 200px;
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
background-size: 200% 100%;
animation: loading 1.5s infinite;
}
Action Plan Ordered by Impact
| Step | Effort | Core Web Vitals Impact |
|---|---|---|
| Set image dimensions | 1 hour | CLS nearly eliminated |
| Optimize hero image | 2 hours | LCP -1s or more |
| Font preloading | 30 minutes | LCP + CLS |
| Lazy loading | 1 hour | LCP + performance |
| Code splitting | 1 day | INP noticeably |
| Redis cache | 1 day | LCP -0.5s+ |
With cloud.net.sa Servers
cloud.net.sa servers in Riyadh and Jeddah achieve TTFB under 50ms for Saudi users. This alone significantly improves LCP. Combined with the other optimizations, achieving LCP < 2s within Saudi Arabia is a realistic goal.
Summary
Core Web Vitals are not dry technical numbers — they are a numerical translation of user experience. Improve LCP and CLS first (easier and more impactful), then move to INP. Every improvement directly affects search ranking and visitor-to-customer conversion rates.
Get Started
Want to try it yourself? Choose the right hosting plan or build your custom server with the specs you need.
