Guides
Detection guide

Frontend Monitoring: Detect Broken Pages and Client Errors

By Sazabi Team

Last verified on Nov 8, 2026.

Frontend breakage is what users see when client code fails: a blank page after a release, a button that does nothing, a checkout that throws in one browser. Your servers can be healthy the whole time. Backend logs show normal traffic and 200 responses while the interface is unusable.

Frontend monitoring means collecting what happens in the browser, then comparing it across releases, routes and browsers to find the change that broke something.

What breaks

  • Uncaught JavaScript exceptions and unhandled promise rejections.
  • Failed network calls from the client: 4xx and 5xx responses, timeouts, blocked requests.
  • Hydration failures in server-rendered apps, where client markup does not match what the server sent.
  • Assets that fail to load, such as a script chunk missing after a deploy.
  • Pages that load but get slower or shift while loading, which overlaps with performance degradation.

What to capture

The browser exposes the hooks. MDN documents that the error event fires on the window for script execution errors thrown synchronously, and that a promise rejected with no handler fires unhandledrejection instead, so you need both listeners. React's hydrateRoot accepts an onRecoverableError callback that React calls when it recovers from an error automatically. Report from it so recovered rendering and hydration problems do not stay silent.

Wrap fetch to log status and duration for each call. Attach to every event the release version, route, browser and a session ID. Without the release, you cannot connect a rise in errors to a deploy.

An example event as it might arrive:

{
  "type": "error",
  "message": "Cannot read properties of undefined (reading 'plan')",
  "route": "/settings/billing",
  "release": "web-2026.11.08.2",
  "browser": "Safari 18",
  "session_id": "s-7c21"
}

Detect it step by step

  1. Group errors by message and top stack frame so that one bug is one group, not thousands of lines.
  2. Find groups first seen after a release. This is the highest-value query because it ties a failure to a change:
-- Example: client error groups that first appeared on the newest release
SELECT error_group, route, count(*) AS events, count(DISTINCT session_id) AS sessions
FROM client_events
WHERE type = 'error' AND release = 'web-2026.11.08.2'
  AND error_group NOT IN (
    SELECT error_group FROM client_events
    WHERE release <> 'web-2026.11.08.2' AND ts >= now() - interval '14 days')
GROUP BY error_group, route
ORDER BY sessions DESC;
  1. Track the share of sessions with at least one error per route and release. Count sessions, not events, so one looping page does not dominate.
  2. Track failed fetch rate per endpoint from the client's point of view. It catches problems your server logs miss, such as blocked or timed-out requests.
  3. Watch Core Web Vitals in the field. web.dev recommends measuring at the 75th percentile of page loads, segmented by mobile and desktop, with targets of 2.5 seconds or less for Largest Contentful Paint, 200 milliseconds or less for Interaction to Next Paint and 0.1 or less for Cumulative Layout Shift. See web vitals regressions.

Thresholds and pitfalls

Compare against the previous release on the same route and browser, not against a global number. A new group seen by one session is probably noise. A new group seen by 2 percent of sessions on a core route is not.

  • Browser extensions, bots and old browsers add errors that no code change will fix. Filter on user agent and on stack frames that point outside your bundle.
  • Ad blockers and privacy tools drop telemetry, so absence of events is not proof of health. Compare client counts with server request counts per route.
  • Minified stacks are unreadable and group badly. Upload source maps at release time.
  • Releases serve several versions at once while caches expire. Segment by release, not by date.
  • Sampling hides rare breakage on small routes. Keep errors at 100 percent and sample only success events.

What to do when it fires

Check which release introduced the group and whether a flag can switch the change off. Roll back if the route is critical, otherwise fix forward. Confirm with the same query that the group stops on the new release. Add a test for the case that slipped through.

Where Sazabi fits

Sazabi detects client errors, meaning JavaScript exceptions, failed fetches and hydration errors, for every production project with no setup. The frontend breakage detection page shows what an issue looks like. Related guides: client errors, rage clicks and the user and client behavior overview. The Sazabi browser SDK page explains how browser data reaches Sazabi.

With Sazabi

Sazabi detects this today with no setup: the Sazabi agent automatically sets up sensors for your project and maintains them over time. Frontend Breakage Detection: Issues When Your Web or Mobile UI Breaks covers what it catches.

Frequently Asked Questions

What should frontend monitoring capture?

Uncaught exceptions, unhandled promise rejections, failed network calls, hydration errors and field performance, each tagged with release, route and browser.

Why do backend logs miss frontend breakage?

The server can return 200 for every request while client code throws. The failure exists only in the browser.

How do I tie a client error to a deploy?

Attach the release version to every client event and query for error groups that first appear on the newest release.

Which Core Web Vitals targets should I use?

web.dev gives good targets of 2.5 seconds or less for LCP, 200 milliseconds or less for INP and 0.1 or less for CLS, measured at the 75th percentile.

Sources

  1. The error event fires for script execution errors thrown synchronously; unhandled promise rejections fire unhandledrejection instead (accessed Nov 8, 2026)
  2. unhandledrejection event for a promise rejected with no handler (accessed Nov 8, 2026)
  3. hydrateRoot onRecoverableError callback (accessed Nov 8, 2026)
  4. Measure Core Web Vitals at the 75th percentile of page loads, segmented by mobile and desktop (accessed Nov 8, 2026)
  5. Good LCP is 2.5 seconds or less (accessed Nov 8, 2026)
  6. Good INP is 200 milliseconds or less (accessed Nov 8, 2026)
  7. Good CLS is 0.1 or less (accessed Nov 8, 2026)
  8. Sazabi browser SDK captures errors, console, network and interaction events; PostHog and Sentry SDK events can be forwarded (accessed Nov 8, 2026)