What are Core Web Vitals
What are Core Web Vitals
Core Web Vitals are a set of metrics defined by Google that measure real-world user experience on web pages.
The Three Core Web Vitals
- Largest Contentful Paint (LCP) - Measures loading performance
- Interaction to Next Paint (INP) - Measures interactivity
- Cumulative Layout Shift (CLS) - Measures visual stability
Why CWV Matters
- SEO: Google uses CWV as a ranking signal
- User Experience: Better metrics correlate with better UX
- Business Impact: Faster sites have higher conversion rates
- Competitive Advantage: Better performance than competitors
CWV Thresholds
| Metric | Good | Needs Improvement | Poor |
|---|---|---|---|
| LCP | ≤ 2.5s | ≤ 4.0s | > 4.0s |
| INP | ≤ 200ms | ≤ 500ms | > 500ms |
| CLS | ≤ 0.1 | ≤ 0.25 | > 0.25 |
Measuring Tools
// Web Vitals library
import { onLCP, onINP, onCLS } from 'web-vitals';
function sendToAnalytics(metric) {
console.log(metric);
// Send to your analytics service
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
Lab vs Field Data
Lab Data (Lighthouse):
- Controlled environment
- Consistent results
- Good for debugging
- Doesn't reflect real users
Field Data (CrUX):
- Real user data
- Varies by device/network
- Google Search Console
- More representative
Measuring CWV
Measuring CWV
Using web-vitals Library
// utils/web-vitals.js
import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals';
const vitals = [];
function handleVital(metric) {
vitals.push({
name: metric.name,
value: metric.value,
rating: metric.rating, // 'good', 'needs-improvement', 'poor'
delta: metric.delta,
id: metric.id,
navigationType: metric.navigationType,
});
// Send to analytics
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/vitals', JSON.stringify({
...metric,
page: window.location.pathname,
userAgent: navigator.userAgent,
}));
}
}
onLCP(handleVital);
onINP(handleVital);
onCLS(handleVital);
onFCP(handleVital);
onTTFB(handleVital);
export function getVitals() {
return vitals;
}
React Integration
// hooks/useWebVitals.js
import { useEffect } from 'react';
import { onLCP, onINP, onCLS } from 'web-vitals';
export function useWebVitals(callback) {
useEffect(() => {
const handleMetric = (metric) => {
callback(metric);
};
onLCP(handleMetric);
onINP(handleMetric);
onCLS(handleMetric);
return () => {
// Cleanup if needed
};
}, [callback]);
}
// Usage
function App() {
const handleVital = useCallback((metric) => {
console.log(`${metric.name}: ${metric.value}`);
analytics.track('web-vital', metric);
}, []);
useWebVitals(handleVital);
return <Router />;
}
Chrome DevTools
- Performance Panel: Record and analyze page load
- Lighthouse: Automated performance audit
- Performance Metrics: Real-time CWV in DevTools
PageSpeed Insights
- Comboses lab and field data
- Shows CWV from Chrome UX Report
- Provides optimization suggestions
- Free API available
Lighthouse CI
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [push]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- run: npm run build
- uses: treosh/lighthouse-ci-action@v9
with:
urls: |
http://localhost:3000/
http://localhost:3000/products
budgetPath: ./lighthouse-budget.json
Improving CWV
Improving CWV
LCP Improvements
// 1. Optimize hero image
function HeroSection() {
return (
<div className="hero">
<img
src="/hero-image.webp"
alt="Hero"
width="1200"
height="600"
fetchPriority="high"
decoding="async"
/>
</div>
);
}
// 2. Preload critical resources
function Head() {
return (
<head>
<link rel="preload" href="/hero-image.webp" as="image" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="dns-prefetch" href="https://api.example.com" />
</head>
);
}
INP Improvements
// 1. Break up long tasks
function processLargeDataSet(data) {
const chunks = chunkArray(data, 100);
return chunks.reduce((promise, chunk) => {
return promise.then(() => {
return new Promise((resolve) => {
requestIdleCallback(() => {
processChunk(chunk);
resolve();
});
});
});
}, Promise.resolve());
}
// 2. Use web workers for heavy computation
const worker = new Worker('/workers/computation.js');
function useHeavyComputation(data) {
const [result, setResult] = useState(null);
useEffect(() => {
worker.postMessage(data);
worker.onmessage = (e) => setResult(e.data);
}, [data]);
return result;
}
CLS Improvements
// 1. Always set dimensions on images
function ResponsiveImage({ src, alt, width, height }) {
return (
<img
src={src}
alt={alt}
width={width}
height={height}
style={{ aspectRatio: `${width}/${height}` }}
/>
);
}
// 2. Reserve space for dynamic content
function AdBanner() {
const [ad, setAd] = useState(null);
return (
<div className="ad-container" style={{ minHeight: 250 }}>
{ad ? <AdUnit ad={ad} /> : <AdPlaceholder />}
</div>
);
}
// 3. Use CSS aspect-ratio
.video-container {
aspect-ratio: 16 / 9;
width: 100%;
}
Quick Wins Checklist
- Enable text compression (Brotli/Gzip)
- Serve images in modern formats (WebP/AVIF)
- Use
loading="lazy"for below-fold images - Preload critical resources
- Minimize render-blocking resources
- Use
content-visibility: autofor long pages - Implement proper caching headers
Practice Problems
Create a reusable React component implementing Core Web Vitals. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for Core Web Vitals using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize Core Web Vitals for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. What are the three Core Web Vitals?
2. What is a good LCP score?
3. What does CLS measure?
4. Why is field data more valuable than lab data?
5. How can you improve INP?
Flashcards
Question
What does LCP measure?
Click to reveal answer
Answer
Loading performance - how quickly the largest content element becomes visible.
Question
What does INP measure?
Click to reveal answer
Answer
Interactivity - the delay between user interaction and visual response.
Question
What does CLS measure?
Click to reveal answer
Answer
Visual stability - unexpected layout shifts during page load.
Question
What is the web-vitals library?
Click to reveal answer
Answer
A library by Google that measures Core Web Vitals in the browser.
Question
What is Core Web Vitals?
Click to reveal answer
Answer
Core Web Vitals is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.Core Web Vitals are LCP, INP, and CLS
- 2.Good LCP is ≤ 2.5s, good INP is ≤ 200ms, good CLS is ≤ 0.1
- 3.Use the web-vitals library to measure real user metrics
- 4.Field data is more valuable than lab data for UX
- 5.Quick wins include image optimization, code splitting, and reserving space
Interview Tips
- •Explain what each Core Web Vital measures
- •Discuss strategies for improving LCP, INP, and CLS
- •Know the difference between lab and field data
Cheat Sheet
Core Web Vitals Cheat Sheet
Metrics
| Metric | Good | Poor |
|---|---|---|
| LCP | ≤ 2.5s | > 4.0s |
| INP | ≤ 200ms | > 500ms |
| CLS | ≤ 0.1 | > 0.25 |
Quick Fixes
- LCP: Preload images, optimize server response
- INP: Break long tasks, use web workers
- CLS: Set image dimensions, reserve space
Tools
- web-vitals library
- Lighthouse
- PageSpeed Insights
- Chrome DevTools