Understanding Web Vitals: Key Metrics to Improve Your Application's Performance

Table of contents
- What Are Core Web Vitals?
- How to Measure Your Core Web Vitals
- How to measure Core Web Vitals on a React Project:
- Let’s see how to debug the LCP scores:
- Ways to Improve Web Vitals
- Performance Optimization for React Apps
- 1. Code Splitting
- 2. Optimize State Management
- 3. Minimize re-renders
- 4. Minimize Props Drilling
- 5. Lazy Load Images and Components
- 6. Implement Server-Side Rendering (SSR) or Static Site Generation (SSG)
- 7. Optimize Dependencies
- 8. Enable Gzip or Brotli Compression
- 9. Cache Resources
- 10. Monitor Performance Continuously
- Conclusion

In today's fast-paced digital world, user experience is paramount. Google recognises this and has introduced Core Web Vitals as a set of metrics to measure and improve the user experience on the web. These metrics are now a crucial part of Google's ranking algorithm, making them essential for developers and SEO professionals alike.
In this blog, we’ll dive into what Core Web Vitals are, why they matter, and how you can measure and optimise them. We’ll also explore how to implement these optimisations in a React application.
What Are Core Web Vitals?
Core Web Vitals are a subset of Web Vitals that focus on three key aspects of user experience:
Loading Performance (Largest Contentful Paint - LCP)
Interactivity (Interaction to Next Paint - INP)
Visual Stability (Cumulative Layout Shift - CLS)
These metrics are designed to help developers understand how users perceive the performance and usability of a website.
1. Largest Contentful Paint (LCP)
LCP measures the time it takes for the largest content element (e.g., an image, video, or block of text) to become visible within the viewport. A good LCP score is 2.5 seconds or faster.
Why it matters: Users want to see meaningful content as quickly as possible. A slow LCP can lead to frustration and higher bounce rates.
2. Interaction to Next Paint (INP)
Measures interactivity by evaluating the time it takes for the browser to respond to user inputs (e.g., clicks, taps, or key presses). A good INP score is less than 200 milliseconds.
Why it matters: A responsive website ensures users can interact with it seamlessly, improving engagement and satisfaction.
3. Cumulative Layout Shift (CLS)
CLS measures the visual stability of a page by quantifying how much the layout shifts during the loading process. A good CLS score is less than 0.1.
Why it matters: Unexpected layout shifts can be frustrating, especially when users are trying to interact with the page.
How to Measure Your Core Web Vitals
There are several tools available to measure Core Web Vitals:
Google PageSpeed Insights: Provides a detailed analysis of your website’s performance, including Core Web Vitals.
Lighthouse: A tool integrated into Chrome DevTools that audits performance, accessibility, and more.
Chrome User Experience Report (CrUX): A dataset that provides real-world user experience data.
Web Vitals Library: A JavaScript library to measure Core Web Vitals programmatically.
How to measure Core Web Vitals on a React Project:
Using web-vitals
Library
Google provides the web-vitals
library to measure these metrics easily. Here’s how you can integrate it into your React project:
npm install web-vitals
Create a file, webVitals.ts
Then import these functions to measure core web vitals in your React project:
import { onCLS, onLCP, onINP } from "web-vitals";
const sendToAnalytics = (metric) => {
console.log(metric);
// Send metric to analytics server (Optional)
};
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
onCLS(sendToAnalytics);
Now finally import that web vitals file to your React project file. Here I have imported that file into my fresh Vite-React project.
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";
import "./webvitals"; // core web vitals
function App() {
const [count, setCount] = useState(0);
return (
<>
<div>
<a href="<https://vite.dev>" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="<https://react.dev>" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
Now run the project on the dev server and view it in the browser. Open the inspect panel to see the console. Now reload the page and notice the console.
Opps!! didn’t see anything🤨. Don’t warry. Most people get stuck here. !! Just switch the tab and come back and watch the console again.😉 You will see something like this:
These are the core web vitals scores you are looking for. Now what??
Let’s see how to debug the LCP scores:
To improve the score, you have to understand those projected objects . Suppose LCP measures the time it takes for the largest content element. So you need to find the largest element on your webpage, and you have to reduce the render time of it, right?
Now expand the LCP object. You will see the LCP score. Also the largest element on your webpage with its score. In this scenario, Vite+React text is the largest element on this webpage. Beside, generally, you will also notice it easily that this text is occupying a large amount of area in my webpage.
Here, core web vitals also give you certain informations like render time, score, size, etc. These will help you better understand the largest element so that you can perform optimisations on it. Now, Its showing “good” on my page. But if I add a delay to render the text. What will happen? Lets see:
const [showText, setShowText] = useState(false);
// Simulate a fake delay to render the "Vite + React" text
useEffect(() => {
const delay = 4000; // 2 seconds delay
const timer = setTimeout(() => {
setShowText(true);
}, delay);
// Cleanup the timer to avoid memory leaks
return () => clearTimeout(timer);
}, []);
// largest text
{showText ? <h1>Vite + React</h1> : <p>Loading...</p>}
After doing this, save and reload the page. Wait for the text to render, then switch tabs and come back to see the score.
Here the score is poor, right!!. It’s because the Vite+React text is the largest text which took 4319.300000071526 ms or 4319.300000071526/1000
=4.3
seconds to load. Also, you can see that we added a 4-second delay in the code. That’s why the score is poor.
Like these, you can measure other score metrics as well.
Ways to Improve Web Vitals
Improving LCP
Optimise images:
Use modern formats like WebP.
Implement lazy loading for offscreen images.
Use a content delivery network (CDN).
Minimise render-blocking resources like CSS and JavaScript.
Preload important assets (e.g., hero images, fonts). Or you can use NextJS
Image
component<link rel="preload" href="/path-to-image.jpg" as="image" />
Improving INP
Reduce JavaScript execution time:
Split code using dynamic imports.
const LazyComponent = React.lazy(() => import('./Component')); <Suspense fallback={<div>Loading...</div>}> <LazyComponent /> </Suspense>;
Use tree-shaking to remove unused code.
Optimise third-party scripts.
Defer non-essential JavaScript. Use
React.useEffect
for tasks that don't need to block rendering.Use web workers to offload heavy computations.
Improving CLS
Specify dimensions for images and videos to prevent layout shifting.
Avoid inserting content dynamically above existing content.
Use CSS to reserve space for ad banners or dynamic elements.
Performance Optimization for React Apps
1. Code Splitting
Split your code into smaller bundles using React's lazy loading and dynamic imports:
const LazyComponent = React.lazy(() => import('./LazyComponent'));
2. Optimize State Management
Avoid excessive re-renders by using memoization (
React.memo
,useMemo
,useCallback
).Use efficient state management libraries like Redux Toolkit or Zustand.
3. Minimize re-renders
Ensure components only re-render when necessary by using React.memo
.
4. Minimize Props Drilling
Use context or state management tools to avoid excessive prop passing.
5. Lazy Load Images and Components
Lazy load components and images to reduce initial load time.
6. Implement Server-Side Rendering (SSR) or Static Site Generation (SSG)
- Use frameworks like Next.js to pre-render content and improve loading performance.
7. Optimize Dependencies
Audit your dependencies to remove unused or large packages.
Use lightweight alternatives where possible.
8. Enable Gzip or Brotli Compression
Ensure the server compresses assets before sending them to the client.
9. Cache Resources
Use browser caching to store frequently accessed resources.
10. Monitor Performance Continuously
- Integrate performance monitoring tools like Lighthouse, New Relic, or Sentry to track and improve performance over time. I prefer sentry as its open-source and sends real-time updates about your website
Conclusion
Web Vitals provide a robust framework to measure and enhance the user experience of any website or web application. By focusing on metrics like loading performance, interactivity, and visual stability, they help developers optimise site performance, ensuring faster load times, reduced user frustration, and improved retention. Ultimately, addressing these metrics not only boosts user satisfaction but also contributes to better search engine rankings and increased traffic.
Subscribe to my newsletter
Read articles from Ashikur Rahman directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Ashikur Rahman
Ashikur Rahman
Hi there! 👋 I'm a frontend developer with hands-on experience building intuitive and scalable user interfaces. I specialize in technologies like React, TypeScript, Next.js, and Redux, and I'm driven by a passion for crafting meaningful, user-friendly projects. Currently diving deep into problem-solving and algorithms to refine my developer mindset, I enjoy breaking down complex challenges into elegant solutions. When I’m not coding, you’ll find me contributing to open-source projects or sharing insights about web development, design patterns, and tech trends here on Hashnode. Let’s connect and learn together! 🚀