Measuring performance with tools you trust is the only way to fix real regressions. Stop chasing Lighthouse scores and start tracking actual user metrics.

Last month, my team spent three days hunting a "ghost" regression where our dashboard felt sluggish, yet our Lighthouse score remained a perfect 100. We were optimizing for a synthetic lab environment while our actual users were struggling with a 1.5-second input delay on low-end devices.
If you’re relying solely on synthetic audits, you’re missing the forest for the trees. Real performance is about what the user feels, not what a headless browser reports in a controlled environment.
Synthetic tools like Lighthouse or WebPageTest are fantastic for catching low-hanging fruit. They’re consistent, repeatable, and great for CI/CD gates. But they are not the truth.
A synthetic test runs on a high-speed machine with a clean cache and no competing background processes. Your users are on shaky 4G connections, running three other tabs, and using phones with thermal throttling. When you start measuring performance with tools you trust, you have to prioritize Real User Monitoring (RUM) over lab scores.
We initially tried to fix our perceived slowness by aggressively code-splitting our main bundle. We used React Performance Patterns You Actually Need in 2025 to trim down our component tree, but the lag persisted. It turned out to be an issue with our event handler attachment timing, something a static analysis tool would never flag.

Forget about "Page Load Time." It’s a vanity metric. If you want to know if your app is fast, focus on these three:
We started tracking these using the web-vitals library in production. We pushed the data to an internal logging endpoint. After about two weeks of gathering data, we noticed that 15% of our users were hitting an INP of over 400ms. That’s "unusable" territory.
Don't just collect data—act on it. We built a simple pipeline to bridge the gap between our local development and production reality.
First, add the web-vitals package:
JAVASCRIPTimport { onINP, onLCP, onCLS } from CE9178">'web-vitals'; function sendToAnalytics(metric) { const body = JSON.stringify(metric); // Send to your backend or observability platform navigator.sendBeacon(CE9178">'/api/performance', body); } onINP(sendToAnalytics); onLCP(sendToAnalytics); onCLS(sendToAnalytics);
A high LCP on a desktop machine is a code problem. A high LCP on a budget Android device is an optimization problem. Always segment your data by navigator.deviceMemory or navigator.hardwareConcurrency.
If you're using modern frameworks, watch out for network waterfalls. I’ve written previously about Next.js App Router Data Fetching: Avoiding Performance Waterfalls and how that single architectural choice often ruins your LCP scores. You can have the fastest code in the world, but if your data fetching is sequential, your users are just staring at a spinner.
You might be tempted to track every single interaction. Don't. High-resolution performance monitoring can actually cause the performance issues you're trying to measure.
We once added too many performance.mark calls, which triggered extra garbage collection cycles on older devices. Keep your instrumentation lightweight. Use navigator.sendBeacon to ensure your analytics don't block the main thread or delay the page unload event.
Looking back, I wish we had started with RUM on day one. We spent weeks debating which build-time optimizations were "best" while ignoring the fact that our heavy third-party scripts were the primary culprits for our poor INP.
If you're worried about your stack, check if you're using the right runtime. We recently explored Bun runtime performance: Why it’s the shift you need to speed up our server-side rendering, which bought us about 80ms of head-room on our initial document response.

Q: Should I stop using Lighthouse entirely? No. Use it for regression testing in CI to prevent obvious mistakes. Just don't treat it as your final performance report card.
Q: How do I handle performance data from thousands of users? Don't send every single event. Use a sampling rate. Sending 10% of your traffic's performance data is usually more than enough to identify trends and regressions.
Q: Is INP more important than LCP? It depends on your app type. For a dashboard or a complex tool, INP (responsiveness) is king. For a content site or a blog, LCP (loading speed) matters more.
Ultimately, performance is a moving target. You'll never be "done" optimizing. The goal isn't a perfect score; it’s a UI that feels invisible to the user. Keep measuring, keep segmenting your data, and stop trusting the lab.
Cutting JavaScript bundle size doesn't require a rewrite. Learn how to audit your dependencies, tree-shake dead code, and optimize your build for speed.