Engineering Diaries · Observability
§
ObservabilityFrontendPerformance

Frontend Observability is Not a Backend Problem

Your servers are green. Your APIs are healthy. Your dashboards look perfectly fine. And somewhere out there, a real user is staring at a blank white screen. Here is why that gap exists, and what you can actually do about it.

01 · The Problem

Your Backend is Fine. Your Users Are Not.

A few months back, one of my colleagues pinged me in Slack. "Hey, did you check the frontend errors dashboard?" I had not. Nobody had. We had four Datadog monitors watching our Node services, three PagerDuty alerts for database connection failures, and a very thorough runbook for every possible API outage. What we did not have was any meaningful visibility into what was actually happening inside the browser.

Turned out a third-party font CDN had quietly gone down. Our CSS was loading fine. Our HTML was fine. The JavaScript bundle was fine. But because we had a hardcoded font-display: block on a Google Fonts import that was timing out, an entire section of our checkout page was rendering invisible text on a white background for users in certain regions. Not an error. Not a crash. Just a completely silent, invisible failure that our backend observability had absolutely zero visibility into.

We found out three days later when a support ticket came in. By then, we had no idea how many people had quietly given up and left.

"The backend tells you what your servers experienced. Frontend observability tells you what your users experienced. These are two very different stories, and most teams are only listening to one of them."

This is the core problem. Backend observability has matured beautifully over the last decade. We have distributed tracing, structured logging, APM tools, synthetic monitors, SLOs, error budgets, and entire engineering philosophies built around knowing exactly what our infrastructure is doing at any given moment. Frontend observability, by comparison, is still being treated as an afterthought in most teams I have worked with or spoken to.

And the excuse I hear most often? "That is a frontend problem, not a backend problem." Which is true. It is a frontend problem. That is precisely why the backend team should not be the one solving it, and also precisely why the frontend team keeps not solving it either. It falls in the gap between ownership.

02 · Definition

What We Actually Mean by Frontend Observability

Observability, in the traditional backend sense, means being able to answer arbitrary questions about your system's state by looking at its outputs. You should not need to redeploy or add new instrumentation to understand a production problem. The data should already be flowing.

Frontend observability means the same thing, but for the client. You should be able to answer questions like: what did the user actually see when this error happened? Which browsers are choking on our new CSS grid layout? Is our JavaScript bundle parse time causing bounces on low-end Android devices? Is that third-party analytics script delaying our Largest Contentful Paint by two seconds for users in Southeast Asia?

These are not questions your backend can answer. They require instrumentation that lives in the browser, captures real user experience, and ships that data somewhere you can actually query it.

The Three Pillars, Applied to the Frontend

Logs   JavaScript errors with full stack traces, console warnings, network failures, custom application events.

Metrics   Core Web Vitals (LCP, CLS, INP), bundle sizes, resource load times, client-side API latency, crash rates by browser and device class.

Traces   User session replay, navigation timings, component render waterfalls, distributed traces that stitch together the client-side leg of a request with its server-side journey.

Notice how none of these come for free from your existing backend tooling. You have to instrument them deliberately, at the client level, and you have to build the habit of actually looking at them when things go wrong.

03 · Root Causes

Why Frontend Observability Keeps Getting Ignored

I have asked this question to a lot of engineers across different companies, and the answers cluster around a few common themes. Understanding them is important because fixing the tooling problem without fixing the cultural and organisational problem around it will not actually change anything.

Backend engineers own the dashboards

In most companies, the team that sets up observability infrastructure is the backend or platform team. They are solving for their own pain, which is completely rational. The dashboards they build capture server metrics, database query performance, queue depths, and API error rates. Frontend metrics simply do not show up in these dashboards, so they do not get monitored, and they do not get prioritised.

Frontend engineers, meanwhile, often do not have the access or the familiarity with tools like Datadog, Grafana, or Honeycomb to go and add their own instrumentation. So the gap persists.

Errors in the browser feel less "real"

There is a subtle cultural thing happening here. When your API throws a 500 error, PagerDuty wakes someone up. When your React app throws an unhandled promise rejection in production, nothing happens. Nobody is paged. Nobody wakes up. The error is logged to the browser console of the one user who happened to open DevTools, and then it disappears into the void.

This asymmetry in how we treat errors creates a completely distorted picture of product health. A team can have an error rate of 3 JavaScript exceptions per session and still feel like their product is "stable" because their backend error rate is 0.01%.

The ownership problem is genuinely tricky

Frontend observability sits in an uncomfortable middle space. It is not pure infrastructure, so the platform team does not feel responsible for it. It is not product analytics, so the data team does not feel responsible for it. And frontend engineers are usually too busy building features to instrument the ones they have already shipped. This diffusion of responsibility is probably the single biggest reason why most teams end up with nothing.

A Useful Heuristic If your on-call runbook has more entries about database failover than it does about JavaScript error spikes, you have an ownership problem, not just a tooling problem.
04 · Failure Modes

The Specific Things That Break Without Frontend Observability

Let me be concrete here. These are not theoretical failure modes. These are the kinds of things that have actually happened to real engineering teams, and that would have been caught quickly with even basic frontend instrumentation in place.

Silent JavaScript failures that never surface as HTTP errors

Your backend returns a 200 response with a perfectly valid JSON payload. Your frontend JavaScript then tries to access response.data.user.preferences.theme and throws a TypeError because preferences is null for new users. The user sees a broken page. Your error rate dashboard shows 0.00% API errors. You have no idea this is happening.

This category of error is probably the most common and the most underreported. A study by Sentry found that the majority of JavaScript errors in production are never reported to any monitoring system. They happen, they break the experience for that user, and they vanish.

Third-party script degradation

Modern web applications load scripts from dozens of third-party domains. Analytics, A/B testing, customer support widgets, payment processors, social login SDKs. Any one of these can start misbehaving in ways that degrade your application's performance or functionality without causing a single server-side error. If you are not capturing third-party resource timings and error rates at the client level, you will not know when a vendor you depend on starts having problems.

Browser and device-specific regressions

Your CI pipeline runs tests in a headless Chromium instance on a powerful cloud machine. Your users run Safari on an iPhone 12 with a throttled 4G connection while sitting in a metro train. These are not the same environment. CSS bugs, API incompatibilities, layout shifts, and performance cliffs that only appear on specific browser versions or device classes are extremely common, and absolutely invisible to backend monitoring.

Core Web Vitals degradation

Since Google started using Core Web Vitals in its ranking algorithm, frontend performance has had real SEO and business consequences beyond just user experience. But CWV data only exists in the browser. It is collected by the browser, reported by the browser, and can only be measured meaningfully through real user monitoring. Lab-based testing tools give you a rough approximation, but field data from real users in real conditions is the only thing that actually tells you whether you are hitting thresholds.

70%
JS Errors That
Go Unreported
3x
Higher Bounce Rate
With Poor LCP
48h
Average Time to Detect
Silent Frontend Bugs
23%
Revenue Impact From
Unmonitored UI Failures
05 · Tooling

The Tooling Landscape, Without the Marketing Speak

There are broadly four categories of frontend observability tooling, and you will almost certainly need something from each one. The good news is that the ecosystem has grown up considerably in the last two or three years, and integrating even a basic setup into a React or Vue application takes an afternoon, not a sprint.

Error tracking

This is the starting point. You need something that catches unhandled JavaScript exceptions, captures full stack traces with source map support, groups similar errors intelligently, and sends you an alert when a new error type starts appearing or when a known error suddenly spikes. Sentry is the default choice for most teams and is genuinely excellent. Datadog has a good frontend error tracking product if you are already in that ecosystem. Rollbar and Bugsnag are solid alternatives.

If you are using React, you need to wrap your application in an Error Boundary component in addition to the global error handler, because React swallows certain render-phase errors that the global window.onerror handler will never catch.

Real User Monitoring

RUM tools capture performance data from actual user sessions. They measure when resources finish loading, when the page becomes interactive, what the layout shift score is, and how long your LCP element took to paint. This is different from Lighthouse or WebPageTest, which measure performance in synthetic controlled conditions. RUM gives you field data: what real users on real networks with real devices are actually experiencing.

Datadog RUM, New Relic Browser, and Elastic RUM are the enterprise options. SpeedCurve and Calibre are excellent if you want something more focused purely on web performance. If budget is a constraint, the Web Vitals JavaScript library combined with your own analytics pipeline is a perfectly viable DIY approach.

Session replay

Session replay tools record user sessions and let you play them back like a video. When a bug report comes in saying "the checkout button doesn't work," you can watch exactly what the user did, what the page looked like when they clicked it, what JavaScript errors were active at that moment, and what network requests were failing in the background. This collapses a debugging loop that used to take days into something you can resolve in minutes.

LogRocket is the most capable tool in this space and has good integration with error tracking. Hotjar does session replay but is more analytics-focused and has weaker error correlation. FullStory is powerful but expensive. PostHog has a session replay feature if you are already using it for product analytics and want one fewer tool to manage.

Distributed tracing that crosses the client boundary

This is where things get genuinely interesting and where most teams have not gone yet. When a user clicks a button that triggers a request, you want a trace that starts at the click handler in the browser, follows the request through your CDN, into your API gateway, down through your microservices, and back out again, all as a single connected trace. OpenTelemetry now has a browser SDK that makes this possible, and if you are already running OTel on the backend, adding the frontend leg is not as painful as it sounds.

Frontend Observability Stack · Recommended Layers
Browser Agent
Error Tracker
RUM Platform
Alerting
Session Replay
OTel SDK (Browser)
Trace Backend
Shared Dashboard
06 · Implementation

How to Actually Instrument This, Starting From Zero

Theory is fine, but let us talk about what the code actually looks like. The following examples assume a React application, but the patterns apply to any modern JavaScript framework with minor syntax differences.

Step one: global error capture

Before you reach for any third-party tool, add a global error handler that captures everything the browser sees. This is your safety net for anything that falls outside structured error boundaries.

global-error-handler.ts
// Catches unhandled exceptions
window.addEventListener('error', (event) => {
  reportError({
    type: 'uncaught_exception',
    message: event.message,
    filename: event.filename,
    stack: event.error?.stack,
    url: location.href,
    userAgent: navigator.userAgent,
    timestamp: new Date().toISOString(),
  });
});

// Catches unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
  reportError({
    type: 'unhandled_promise_rejection',
    message: event.reason?.message ?? 'Unknown rejection',
    stack: event.reason?.stack,
    url: location.href,
    timestamp: new Date().toISOString(),
  });
});

Step two: the React Error Boundary

React's component rendering lifecycle throws errors in a way that bypasses the global handler. You need a dedicated Error Boundary component wrapping your application tree, and ideally wrapping individual feature areas separately so one broken widget does not take down the whole page.

ErrorBoundary.tsx
import { Component, ReactNode } from 'react';

class ErrorBoundary extends Component<
  { children: ReactNode; fallback?: ReactNode },
  { hasError: boolean }
> {
  state = { hasError: false };

  static getDerivedStateFromError() {
    return { hasError: true };
  }

  componentDidCatch(error: Error, info: ErrorInfo) {
    reportError({
      type: 'react_error_boundary',
      message: error.message,
      stack: error.stack,
      componentStack: info.componentStack,
    });
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback ?? <FallbackUI />;
    }
    return this.props.children;
  }
}

Step three: measure Core Web Vitals from the field

The web-vitals npm package from Google makes this trivially easy. You install it, call four functions, and you have real field data for every metric that matters to your ranking and your users.

vitals.ts
import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals';

const sendToAnalytics = (metric) => {
  fetch('/api/vitals', {
    method: 'POST',
    body: JSON.stringify({
      name:  metric.name,
      value: metric.value,
      rating: metric.rating, // 'good' | 'needs-improvement' | 'poor'
      url: location.href,
      deviceType: getDeviceClass(),
    }),
    keepalive: true,
  });
};

onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
onFCP(sendToAnalytics);
onTTFB(sendToAnalytics);

That keepalive: true is important. Users navigate away from pages, and a normal fetch will get cancelled when they do. keepalive tells the browser to finish the request even if the page is already closing.

07 · Alerting

What to Actually Alert On (And What Not To)

One of the failure modes I see when teams first set up frontend error tracking is alert fatigue. They turn on Sentry, get a thousand errors on day one, set up email notifications for each one, and within a week everyone has started ignoring the notifications. This is not an observability win. It is noise generation.

The goal is not to know about every JavaScript error. The goal is to know about errors that are actually impacting users, to detect regressions quickly after deploys, and to have a meaningful signal you can act on.

Alert on new error types, not all errors

A good error tracking tool will group errors by fingerprint and tell you when a new error type appears for the first time. That deserves an alert. An error that has been happening at a steady rate for six months does not need to page anyone at 2am. It needs to be on the backlog.

Alert on error rate spikes post-deploy

Compare your JavaScript error rate in the 30 minutes after a deployment to the baseline from the previous period. A spike is a regression. This single alert catches the majority of bugs introduced by new code, and it catches them before support tickets start arriving.

Alert on Core Web Vitals crossing thresholds

Google's recommended thresholds are well-established: LCP under 2.5 seconds, CLS under 0.1, INP under 200ms. Set up weekly or daily aggregations and alert if your p75 field data starts crossing into "needs improvement" territory. Do not alert on individual data points, because there is too much natural variance.

The Rule of 1% If an error is affecting more than 1% of your sessions, it deserves immediate attention regardless of how it looks in the backend. If it is under 0.1%, log it, track it, but do not break anyone's flow to fix it today. Between those two numbers, use your judgment about the severity of the user impact.

Do not alert on everything from bots and crawlers

A significant fraction of JavaScript errors in production come from bots, search engine crawlers, and browser extensions injecting code into your pages. Before you set up alerting, spend time filtering these out. Check the user agent string, filter out sessions with impossibly fast interaction rates, and exclude known crawler IPs. Otherwise you will spend a lot of time debugging errors that no real human ever experienced.

08 · Ownership

Solving the Ownership Problem Structurally

Tooling without ownership does not work. You can have the best Datadog RUM setup in the world, and if nobody has a clear responsibility for looking at it and acting on what it shows, it will slowly become shelfware. The organisational fix matters as much as the technical one.

Put frontend metrics in the same dashboard as backend metrics

This sounds small but it makes a huge difference. If your engineering team's shared operations dashboard shows backend error rates, database latency, and queue depths but does not show JavaScript error rate, LCP p75, and session crash rate, then frontend health is not treated as a first-class operational concern. Put it in the same view. Make it part of the same on-call runbook. The moment leadership and backend engineers start seeing frontend metrics alongside their own, the culture shifts.

Make frontend observability part of the definition of done

For any feature that goes to production, the pull request should not be mergeable without a clear answer to: what error boundary covers this component? What custom events are we emitting to track user interaction? What do we do if the third-party SDK this feature depends on goes down? This is not extra overhead. It is the same kind of thinking we already apply to backend features when we talk about retry logic, circuit breakers, and fallback strategies.

Rotate frontend observability into on-call

If your on-call rotation only pages people for backend incidents, your implicit message is that frontend failures are not incidents. Consider adding a weekly or monthly frontend health review to your incident management process, and treat JavaScript error rate spikes with the same urgency as API error rate spikes. The business impact is often the same or worse, because broken frontend code directly touches the user experience in a way that a degraded internal microservice often does not.

"Observability is not about having data. It is about having data that changes what you do. If your frontend metrics are not influencing your sprint priorities, your on-call decisions, and your architecture choices, they are not really observability. They are just logging."

09 · Common Mistakes

Mistakes Teams Make After Getting This Set Up

Setting up frontend observability is genuinely not that hard. The harder part is not making the mistakes that quietly undermine it after you have done the initial work.

Not setting up source maps

If you deploy minified JavaScript without uploading source maps to your error tracking tool, every stack trace you see will be completely useless. You will see something like TypeError at bundle.min.js:1:48392 and have no idea which component or function caused it. Source map upload should be a required step in your deployment pipeline, not an optional thing you plan to do later.

Tracking too many custom events

There is a temptation, once you have event tracking set up, to instrument everything. Every button click, every form field focus, every modal open and close. This creates massive event volumes, significant cost on per-event pricing models, and dashboards that are impossible to make sense of. Be selective. Track the events that correspond to meaningful user actions, key funnel steps, and feature adoption signals. You can always add more, but cleaning up a bloated event schema is painful.

Ignoring mobile and low-end devices

Your developers have MacBook Pros with 32GB RAM and fast Wi-Fi. Your users in Tier-2 and Tier-3 cities often use mid-range Android phones on 4G connections that drop out in lifts and metro tunnels. The performance characteristics of these two environments are so different that what feels "fast enough" in development can be genuinely painful in the field. Segment your RUM data by device class from day one, and set up separate alerting thresholds for low-end devices.

Not correlating frontend errors with business outcomes

The most powerful thing you can do with frontend observability data is connect it to business metrics. What is the checkout completion rate for sessions that experienced at least one JavaScript error? How does cart abandonment rate correlate with LCP scores above 4 seconds? These correlations exist, they are usually striking, and they are the most effective way to make the business case for investing more in frontend quality. If you are not building these connections, you are leaving your most persuasive argument on the table.

83%
Teams Without
Source Maps Configured
2s
LCP Threshold Where
Conversions Start Dropping
4x
Faster Bug Detection
With Frontend RUM
1 in 4
Production JS Errors
Affecting Conversions
10 · Where to Start

The Honest Starting Point

If you are reading this and your team has essentially nothing in place, do not try to implement everything at once. Start with one thing, do it properly, and build from there.

  1. Week 1 · Error tracking only. Get Sentry or Datadog browser errors set up, configure source maps, suppress bot traffic, and set up an alert for new error type spikes. That alone will surface problems you did not know existed.
  2. Week 2 to 3 · Core Web Vitals measurement. Add the web-vitals library, start shipping field data to your analytics backend or directly to a monitoring tool. Segment by page, device class, and geography. You will be surprised where the problems are.
  3. Week 4 · Session replay for critical flows. Add session replay to your checkout, signup, or whatever your highest-stakes user flow is. Do not enable it everywhere at first. The ROI is highest where user problems are most costly.
  4. Month 2 · Connect to business metrics. Start correlating your frontend health data with conversion, retention, and engagement. Build the dashboard that shows the relationship between JavaScript error rate and checkout completion. Share it with product and leadership.
  5. Month 3 and beyond · Distributed tracing. If your team is ready, add the OpenTelemetry browser SDK and start stitching together full user request traces from click to response and back. This is where frontend observability truly becomes a first-class engineering practice.

The thing I keep coming back to is that we have spent years getting very good at knowing what our infrastructure is doing. We should spend the same energy getting equally good at knowing what our users are experiencing. These are not separate concerns that belong to different teams. They are two sides of the same question: is the thing we built actually working?

Your backend being healthy is a necessary condition, but it has never been a sufficient one. The user's browser is part of your system. It is time we started treating it that way.

· · ·
Tools Mentioned in This Article

Sentry Datadog RUM LogRocket FullStory PostHog SpeedCurve OpenTelemetry web-vitals New Relic Browser Elastic RUM

None of these are sponsored or affiliated. I have used most of them across different projects and have opinions about all of them. The right tool depends on your existing stack, your team size, and how much you want to manage yourself versus pay someone to manage for you. The web-vitals library from Google is free and open source and is the single best starting point if you want to begin measuring what matters with minimal setup cost.

Opinions expressed here are my own and based on experience across multiple production frontend systems. Statistics cited are drawn from publicly available industry research including reports from Sentry, Google's Web Vitals team, and the HTTP Archive. Your numbers will vary. The only way to know your actual numbers is to start measuring them.