How Do You Know When Your Website Breaks in the Browser?
How Do You Find Out Your Site Is Broken Before Your Client Does?
You instrument the browser, not just the server. Most teams monitor whether the site responds and stop there. That misses the failures that matter most on a marketing site: a script that throws on one browser, a policy that blocks an asset, a form that silently never submits.
We inherit a lot of sites, and this is the most common gap we find. Uptime is green, analytics look normal, and a chunk of visitors have been hitting a broken page for weeks. Nobody knew because nothing was watching the part of the stack the user actually runs.
Here is how we set up front end error monitoring, using the browser features that already exist plus a tool to catch what they cannot.
Why Is Uptime Monitoring Not Enough?
Because it checks the wrong layer. An uptime monitor asks whether your server returned a page. It cannot tell you that the page it returned throws an error in Safari, that a third party script failed to load, or that a content security policy blocked your own analytics. All of those return a healthy 200.
The gap widens on modern sites. Once meaningful behaviour lives in JavaScript, the failure surface moves into the browser, where your server never sees it. A broken interaction is invisible in your access logs.
Uptime monitoring is still worth having, and we set it up on every build. It is the floor, not the ceiling. Our guide to website uptime monitoring covers that layer properly.
What Is the Reporting API and What Does It Cover?
It is the browser's own reporting channel. MDN describes the Reporting API as a generic mechanism for web applications to make reports available for various platform features in a consistent way. It is built into the browser, so it needs no library to produce the reports.
MDN documents eight report types. Content security policy violations arrive as csp-violation reports. Deprecated feature usage arrives as deprecation reports. Browser crashes arrive as crash reports. There are also intervention reports for actions the user agent blocked, plus reports for Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy, Permissions-Policy and Integrity-Policy violations.
That list is worth reading twice, because most of it is invisible to conventional error tracking. A deprecation report tells you a browser vendor is going to break your site on a future release. An intervention report tells you the browser already stopped something you asked it to do. Nothing else in your stack will mention either.
How Do You Collect Reports in JavaScript?
With a ReportingObserver. You create one with a list of report types you care about, then call its observe method to start collecting. MDN documents three methods on it: observe to start, takeRecords to pull whatever is currently queued, and disconnect to stop.
Set the buffered option to true when you create it. MDN notes this lets you retrieve reports that were generated before the observer existed, which matters because the interesting failures usually happen during page load, before your monitoring code has run.
MDN is direct about the tradeoff. The JavaScript approach is easier to set up and needs no server infrastructure, but it is not failsafe, because a page crash can prevent report retrieval. It also runs in Web Workers, which is useful if meaningful work happens off the main thread.
Why Should You Send Reports to a Server Instead?
Because the worst failures kill the observer. MDN points out that crash reports cannot be observed in JavaScript at all, for the obvious reason that a crashed page cannot run code to observe its own crash. Server endpoints are the only way to see those.
The mechanism is straightforward. Reports are sent by POST with a content type of application/reports+json. MDN notes the payload is the JSON serialization of the report with two extra fields added: user_agent and age. You need an endpoint that accepts that and writes it somewhere you will actually look.
MDN also states plainly that there is no absolute guarantee of delivery, because a sufficiently serious error can prevent report collection entirely. Treat the numbers as a floor on what went wrong, never as a complete count.
Which Header Should You Use in 2026?
Reporting-Endpoints, not Report-To. MDN is explicit that Report-To is no longer part of the Reporting API specification. Some browsers still support it for backward compatibility, and it remains in use for Network Error Logging, but MDN says to prefer Reporting-Endpoints for future support.
The newer header takes named endpoints, so you can route different report types to different collectors. A default endpoint catches crash, deprecation and intervention reports. A separate named endpoint can take content security policy violations through the report-to directive on your CSP header.
If you are already sending CSP violation reports somewhere, this is a small change with real value, because the same infrastructure then picks up deprecation and intervention reports for free. We cover the policy side in our content security policy guide.
Why Are Your Stack Traces Unreadable?
Because your production JavaScript is minified and the source map never reached your error tool. This is the single most common reason error monitoring gets abandoned. The errors arrive, the stack trace points at column 4,812 of a bundle, and nobody can act on it.
Sentry's documentation explains its approach: by default it links source maps by injecting Debug IDs into the build output, and it provides native plugins for webpack, Rollup, Vite and esbuild. For build tools outside that list, its documentation points you at the Sentry CLI instead.
There is one requirement that catches people out, and Sentry states it directly: verify artifacts are uploaded before errors occur. Upload source maps after an error has already been captured and that error stays unreadable. Its documentation also notes source maps are only generated and uploaded during production builds, so a working local setup proves nothing.
What Should You Actually Alert On?
New errors and rate changes, not error volume. A site with a steady background of one noisy third party error does not need a nightly email about it. What you want to know is that an error appeared that was not there before your last deploy, or that a known error suddenly affects ten times more sessions.
Group by release. If your error tool knows which build each error came from, the question changes from what is broken to what did we break, and that is answerable in minutes rather than days. This is the single highest value configuration step and it is usually skipped.
Then filter aggressively. Browser extensions, ad blockers and bot traffic generate errors you cannot fix, and an alert channel full of noise gets muted within a fortnight. A monitoring setup nobody reads is worse than none, because it creates the belief that someone is watching.
How Does This Fit a Marketing Site Rather Than an App?
The failures are different and mostly cheaper to fix. On a marketing site the top offenders are third party scripts, embedded forms, video players and tag managers. None of them is your code, all of them can break your page, and the vendor will not tell you when they do.
Conversion paths deserve their own attention. An error on a blog post is a nuisance. The same error on the pricing page or the demo form is lost pipeline. We tag the pages that matter and treat any new error on those as a different severity from everything else.
The forms case is worth calling out because it fails so quietly. A submission handler that throws produces no visible message, no server log and no analytics event. The visitor thinks they contacted you, and you never find out. Browser level error reporting is the only thing that surfaces it.
What Would We Set Up First?
Three things, in this order. Put a ReportingObserver on the site with buffered set to true and send what it collects to an endpoint you own. Add the Reporting-Endpoints header with a default endpoint so crash and deprecation reports have somewhere to go. Then add an error tool with source maps uploaded from the production build.
Do the source map step properly the first time or skip the tool entirely. Unreadable stack traces are the reason most of these setups get quietly switched off, and the fix is a build step, not a subscription.
Finally, write down what happens when an alert fires and who receives it. Detection without a response path just moves the problem. Our website incident response plan covers what that document should contain.
If you want a second pair of eyes on a site's monitoring, or you suspect something has been failing quietly for a while, we are happy to take a look. Find us at phoenix.studio.
Want a site that performs like this?
Tell us about your project. We will come back with a clear next step, no pressure.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
Have a project like this?
Tell us where you want to go. We'll tell you how we'd get you there.