Web Vitals are the browser performance signals that tell you whether a page feels fast, stable, and responsive to real users. They are not abstract benchmarks. They are measurements that connect directly to the experience people have when a page loads, renders, and reacts to input.
The most important thing to understand is that Web Vitals are about perceived quality, not just raw code execution. A page can ship quickly and still feel slow if the main content appears late, the layout jumps around, or the interface hesitates when someone tries to use it.
That is why teams use Web Vitals as a practical performance lens. They help you decide which problems matter most before you spend time optimizing the wrong thing.
What Web Vitals are
The term usually refers to a small set of user-centered metrics that describe loading, responsiveness, and visual stability. Today the core group is LCP, INP, and CLS.
type WebVital =
| 'LCP'
| 'INP'
| 'CLS';
function describeVital(vital: WebVital) {
switch (vital) {
case 'LCP':
return 'loading';
case 'INP':
return 'responsiveness';
case 'CLS':
return 'visual stability';
}
}
Why Core Web Vitals get the most attention
Core Web Vitals are the subset Google emphasizes in its guidance. The naming matters because people often say Web Vitals when they actually mean the core trio above.
| Metric | What it tells you | Where to look first |
|---|---|---|
| LCP | How quickly the main content becomes visible | Server speed, image size, critical CSS, render path |
| INP | How responsive the page feels to interaction | JavaScript work, rendering cost, event handling |
| CLS | How stable the layout stays during load and updates | Reserved space, font loading, dynamic content injection |
Largest Contentful Paint
LCP measures how long it takes for the largest visible piece of content in the viewport to appear. In practice, that is often the hero heading, a featured image, or a large text block.
If LCP is slow, the page can feel empty even if the browser is already downloading assets in the background. That is why LCP is closely tied to perceived loading speed.
1 Slow server response
The browser cannot paint meaningful content until the server sends enough HTML to work with.
2 Render-blocking assets
Large CSS or JavaScript bundles can delay the first useful paint more than the markup itself.
3 Late hero media
Images, video posters, and remote assets often become the largest content element, so their loading path matters a lot.
function reportLcp(value: number) {
console.log('LCP:', value);
}
Interaction to Next Paint
INP measures how responsive the page feels when someone interacts with it. It looks at the time between an input event and the next visible paint after that interaction.
That is a better user-facing question than asking whether the event handler itself returned quickly. A handler can finish fast while the UI still feels sluggish because rendering or layout work happens right after it.
function handleSearchInput(nextValue: string) {
setQuery(nextValue);
startTransition(() => {
setFilteredResults(filterResults(nextValue));
});
}
This pattern matters because input should stay responsive even if the derived UI is expensive. The user should feel the interface react before the expensive update finishes.
Cumulative Layout Shift
CLS measures unexpected movement in the layout while the page is loading or updating. It explains why a button suddenly moves under your cursor or why a headline jumps after an image appears.
That kind of movement makes an interface feel unstable and careless. It is often caused by missing dimensions, late-loading fonts, inserted banners, or content that changes size after hydration.
<img src="hero.jpg" width="1200" height="675" alt="Product dashboard" />
That small detail matters. Reserving space for the image prevents the browser from guessing and reduces layout shift.
How to measure Web Vitals in code
You can measure the metrics in the browser using the Performance APIs. In a Next.js app, the cleanest path is often to report them from the client and send the data to your analytics endpoint.
export function reportWebVital(metric: {
name: string;
value: number;
id: string;
}) {
fetch('/api/vitals', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(metric),
});
}
That example is intentionally simple. The point is not the transport. The point is that you capture the metric close to the user experience and move it into a system where you can analyze trends.
A browser observer example
If you want to understand what is happening directly in the browser, you can observe performance entries yourself.
function observeLayoutShift() {
let cls = 0;
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
cls += entry.value;
}
}
console.log('CLS:', cls);
});
observer.observe({ type: 'layout-shift', buffered: true });
return () => observer.disconnect();
}
That pattern is useful during debugging because it shows the score changing while the page runs. You can see whether a banner, modal, font swap, or image load is responsible for the movement.
What usually improves Web Vitals
1 Ship less critical JavaScript
Reducing render-blocking code often improves both LCP and INP because the browser spends less time parsing and executing work before paint.
2 Reserve space for media
Images, ads, embeds, and dynamic UI sections should have predictable dimensions so the page does not shift after layout is already visible.
3 Keep interactions cheap
Split urgent input from expensive rendering so clicks and typing stay responsive even when the data or UI is large.
A practical Next.js pattern
In a Next.js app, it is common to collect vitals in the client and forward them to an endpoint for later analysis.
type MetricPayload = {
name: string;
value: number;
id: string;
};
export async function sendVital(metric: MetricPayload) {
await fetch('/api/vitals', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(metric),
});
}
Once the data is flowing, the real work is comparing pages, releases, and user segments. That is where performance stops being anecdotal and becomes operational.
The useful takeaway
Web Vitals are not just a reporting layer. They are a short list of user experience problems that performance teams can agree on. LCP points to slow loading, INP points to sluggish interaction, and CLS points to unstable layout.
If you only remember one thing, remember this: optimize the experience the user actually feels, not just the code path that looks expensive in isolation.