Your user does not live on the server: measuring real experience
In the previous article I wrote about the Product Engineer role and the importance of understanding impact beyond a release. Today I want to focus on measurement.
When we discuss performance, we think about CPU, memory, response time, errors, and backend latency. But what happens when all of that looks healthy and users still feel the app is slow?
The frontend runs on different devices, networks, and unpredictable conditions. Server metrics are not enough: we need to measure the user experience.
Web Vitals
Google’s Web Vitals provide signals for web quality. Core Web Vitals quantify direct experience through three pillars:
- Largest Contentful Paint (LCP): loading. Main content should appear in under 2.5 seconds.
- Interaction to Next Paint (INP): interactivity. A response should be under 200 ms.
- Cumulative Layout Shift (CLS): visual stability. The target is under 0.1.
How we measure matters. DevTools gives us Lab Data, an idealized scenario. The web-vitals library reports real-user Field Data and gives us a more honest picture.
Error Boundaries
In React, a render error can unmount the interface and leave a blank screen. Error Boundaries catch it and render an alternative interface we control.
That alternative is only the beginning. If it appears a hundred times a day, we need to measure its activation frequency to understand the application’s real health.
Quantifying frustration
Web Vitals can look good and code can be error-free while users remain unhappy:
- Rage clicks: repeated, fast clicks on one element; the UI gives no feedback.
- Dead clicks: a seemingly interactive element does nothing.
- Error clicks: a click immediately throws a JavaScript error.
Tools such as PostHog, Sentry, and LogRocket expose these patterns through session replays and heatmaps. Watching a frustrated user is worth more than a thousand server logs.
Perceived performance
Perceived smoothness matters more than raw speed. The classic elevator example shows why: mirrors did not make the ride faster, but they made it feel shorter.
The same applies to the frontend. A spinner on a blank screen makes 500 ms feel endless; an animated skeleton communicates progress. Optimistic UI, Local-first, and Background Sync help create that feeling.
Conclusion
To understand impact, measure what the user experiences: Core Web Vitals, errors, and frustration. A fast, stable app is still not guaranteed to succeed. Next we need business metrics: are our releases creating real value?