React performance has two sides that are easy to confuse. Web Vitals measure the experience real users feel, such as how fast the page loads and how quickly it responds.
Render performance measures how long React itself spends producing the UI. Each needs its own tool.
Fixing one without the other leaves the page slow in ways your tools never showed you.
Core Web Vitals at a glance
Core Web Vitals are three user-facing metrics that apply to every page.
| Metric | What it measures | Good threshold |
|---|---|---|
| LCP | Loading speed | 2.5 seconds or less |
| INP | Interaction responsiveness | 200 ms or less |
| CLS | Visual stability | 0.1 or less |
LCP is Largest Contentful Paint, the time until the largest visible element renders. INP is Interaction to Next Paint, which replaced First Input Delay in 2024 and covers every interaction, not just the first. CLS is Cumulative Layout Shift, the amount the page jumps while loading.
A page passes when it meets all three targets at the 75th percentile across real visits, not on a single fast load. FCP, TTFB, and TBT support diagnosis but are not Core Web Vitals. FCP and TTFB help trace slow LCP, while TBT is a lab-only proxy for INP because simulated page loads have no real user input.
Measure Web Vitals with the web-vitals library
The web-vitals package wraps the browser's Performance APIs so the numbers match what Chrome reports to Google tools. Install it as a dependency.
npm install web-vitalsThen report each metric as it becomes available. The library exposes one function per metric, and each calls your callback with a metric object.
import { onCLS, onINP, onLCP } from "web-vitals";
function sendToAnalytics(metric) {
const body = JSON.stringify(metric);
navigator.sendBeacon("/analytics", body);
}
onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);The callback receives a metric with a name, value, rating, and id. sendBeacon delivers the data even while the page is unloading. This is field measurement, because it runs on real users' devices.
Some metrics report only after an interaction or tab switch, so INP never fires for a page the user only looked at. For single-page apps, pass reportSoftNavs true to capture metrics per client-side route change in Chromium browsers that support it.
Measure render time with the Profiler
Web Vitals tell you the page is slow, but not which component is responsible. The React Profiler answers that by recording how long each component takes to render.
import { Profiler } from "react";
function onRender(id, phase, actualDuration) {
console.log(`${id} ${phase}: ${actualDuration.toFixed(2)}ms`);
}
export default function App() {
return (
<Profiler id="App" onRender={onRender}>
<ProductList />
</Profiler>
);
}The onRender callback fires on every commit with the id, the phase, and actualDuration. The interactive Profiler tab in React DevTools exposes the same data as a flamegraph, which the Profiler workflow walks through in detail.
actualDuration is the number to watch: it shows how long the subtree really took, while baseDuration estimates the cost without memoization, so the gap between them reveals how much headroom exists.
Field data versus lab data
Field data comes from real users and reflects their devices, networks, and interactions. Lab data comes from your machine or a simulated Lighthouse run. The two disagree often, because a development laptop is far faster than the average phone.
The same code can score differently on a slow phone over 3G than on your machine, which is why the web-vitals library reports from the browser rather than from a build step.
Trust field data for decisions about what to fix. Use lab data to reproduce and verify a fix locally. Record the same interaction in the Profiler on the failing page, and the largest render is usually the fix target.
When a metric fails in the field, open the corresponding React path, such as avoiding expensive calculations, and follow the measure-first workflow to narrow the cause.
Rune AI
Key Insights
- Core Web Vitals are LCP, INP, and CLS.
- Use the web-vitals library to report real-user metrics.
- The Profiler measures React render time.
- Field data reflects real users; lab data reflects your machine.
- Optimize the metric that is actually failing.
Frequently Asked Questions
What are the three Core Web Vitals?
Is INP the new FID?
Conclusion
Measure user-facing Web Vitals in the field with the web-vitals library, and measure React render time with the Profiler. Keep the two separate, and act on field data first, since lab machines rarely match real users.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.