Reporting API and Report-To: Collecting Browser Errors Centrally
AI generated
JS
() =>
JavaScript · Security · Monitoring
Reporting API and Report-To
Collect errors directly from the browser, no custom tracking JS needed

The Reporting API gives browsers a standardized way to automatically report problems like CSP violations, deprecated API usage, or even tab crashes to a central endpoint. Unlike classic error tracking, this happens largely without additional JavaScript and captures cases custom code would never see.

16 min read Report-To ReportingObserver CSP Violations

1. The gap in classic error tracking

Classic frontend error monitoring is usually based on window.onerror, window.addEventListener('unhandledrejection', ...), and explicit try-catch. These mechanisms reliably capture JavaScript runtime errors but are blind to problems that arise at a deeper browser level, such as resources blocked by a Content Security Policy or the use of a browser API marked as deprecated.

This is exactly the gap the Reporting API closes. It defines a channel through which the browser itself, independent of the execution of custom JavaScript, generates structured reports about certain event categories and either sends them to a configured endpoint or makes them available locally via a JavaScript interface.

2. The Report-To header as a configuration mechanism

For the browser to know where reports should be sent, the server defines named destination URLs via the HTTP header Reporting-Endpoints. Earlier implementations used the now superseded Report-To header with a JSON value, modern browsers increasingly follow the simpler Reporting-Endpoints format.

Once an endpoint is named, it can be referenced in other headers, for example in the Content Security Policy via the report-to directive, to send CSP violations there. The browser handles batching and delivery on its own, including retries for failed deliveries, without the page itself needing to stay active.


// Example server response headers (not settable via JS, shown for reference)
// Reporting-Endpoints: default="https://reports.example.com/csp"
// Content-Security-Policy: default-src 'self'; report-to default

// Snippet showing how a server would generate such headers (Node/Express)
app.use((req, res, next) => {
  res.setHeader(
    'Reporting-Endpoints',
    'default="https://reports.example.com/csp"'
  );
  res.setHeader(
    'Content-Security-Policy',
    "default-src 'self'; report-to default"
  );
  next();
});

3. Capturing CSP violations automatically

Without the Reporting API, developers often only notice CSP violations once users complain about broken functionality, since a blocked script or image usually fails silently in the background for the user. With a configured report endpoint, the browser automatically sends a structured report with the blocked URI, the violated directive, and the line in the source code every time a violation occurs.

This makes the Reporting API especially valuable while introducing or tightening a CSP: instead of blindly tightening the policy and waiting for user complaints, it can first be run in report-only mode, while real violations are collected and analyzed in the background before the policy is actually enforced.

4. ReportingObserver for client-side evaluation

Besides server-side collection via headers, the ReportingObserver also allows reacting to reports on the client side without waiting for a server round trip. This is useful for custom debugging during development or to gather additional context before a report is forwarded to a custom analytics system.

The observer is created with a callback function and optional filters for specific report types, and is activated via observe(). Using the buffered: true option, you can even retrieve reports generated before the observer was created, as long as the page is still active.


const observer = new ReportingObserver((reports, observer) => {
  for (const report of reports) {
    console.log('Report type:', report.type);
    console.log('URL:', report.url);
    console.log('Body:', report.body);

    // Example: forward to an internal dashboard
    fetch('/internal/browser-reports', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        type: report.type,
        url: report.url,
        body: report.body,
      }),
    });
  }
}, { types: ['deprecation', 'intervention'], buffered: true });

observer.observe();

5. Spotting deprecation warnings and interventions early

Browsers regularly mark APIs as deprecated before removing them, for example old synchronous XHR calls on the main thread or certain outdated DOM methods. These warnings normally only appear in the developer console and are never seen by real users, which means a team often only learns about the usage in production after the feature has actually been removed.

Via the deprecation report type, such warnings can be collected centrally from all users, not just from developers who happen to have the console open. This allows proactively identifying deprecated code paths in your own application or in third-party scripts, long before a browser update actually removes the feature and users are affected. This is especially valuable for third-party scripts whose source code you cannot inspect yourself, but whose deprecation warnings still become visible via your own reporting endpoint as soon as they execute in the context of your page.

6. Crash and intervention reports

A particularly valuable report type is crash, which fires when a tab crashes or is terminated due to memory exhaustion, a state that classic JavaScript error tracking naturally cannot capture, since the tab is no longer executing any code at that point. The report is instead created by the browser process itself and delivered at the next possible opportunity.

Something similar applies to intervention reports, which arise when the browser actively steps in against problematic behavior, for example blocking autoplay audio without user interaction. These signals point out where the application violates browser heuristics for good user experience, often things that simply do not show up in your own testing.

Crash reports in particular provide insights in practice that would otherwise only surface through indirect signals like support tickets or a noticeably high bounce rate on certain pages. A team that systematically evaluates crash reports by affected route, browser version, and memory footprint can spot patterns, for example a specific image gallery component that regularly causes memory exhaustion on older mobile devices, long before enough users actively complain.

7. Privacy and the scope of reports

Since reports can contain information such as URLs, user agent data, and technical details, your own reporting endpoint must be treated like any other data collection under privacy law. It is advisable to restrict the endpoint to your own infrastructure and not forward reports unchecked to third parties.

For CSP reports specifically, an additional concern is that blocked URIs can contain sensitive information like internal system names or query parameters if an attacker tries to exfiltrate data via the blocked resource. Server-side filtering and regular cleanup of collected reports are therefore part of a clean reporting setup.

8. Browser support and practical limits

Chrome and other Chromium-based browsers broadly support the Reporting API including Report-To or Reporting-Endpoints, Firefox and Safari have parts of it, particularly CSP reporting via report-uri or report-to, but not always the full ReportingObserver feature set. A production setup should therefore not rely exclusively on client-side evaluation.

In practice, a combination proves effective: server-side endpoints for all supported report types as the primary data source, supplemented by a ReportingObserver for browsers that support it, to attach additional client-side context like the current user route to the report before it is forwarded. It is also worth regularly reviewing incoming report statistics by browser family, to spot early when a specific browser suddenly reports noticeably more violations or deprecation warnings than before, a strong signal of a recently rolled out browser update with changed behavior.

9. A complete example setup

A complete reporting setup combines server-side header configuration with a client-side observer that adds extra context, such as which route the user currently visits or which feature flags are active. This produces reports that describe not just the technical problem but also the circumstances under which it occurred.

The table below compares the most important report types, their triggers, and whether they are visible client-side via the ReportingObserver or only server-side via the configured endpoint.


function initReporting(currentRoute) {
  if (!('ReportingObserver' in window)) return;

  const observer = new ReportingObserver((reports) => {
    for (const report of reports) {
      fetch('/internal/browser-reports', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          type: report.type,
          url: report.url,
          body: report.body,
          route: currentRoute,
          timestamp: Date.now(),
        }),
      });
    }
  }, { buffered: true });

  observer.observe();
}

initReporting(window.location.pathname);
Report type Trigger Visible via ReportingObserver Typical use
csp-violation Resource blocked by a CSP directive Partially, browser dependent Test CSP rollout without user complaints
deprecation Use of an API marked as deprecated Yes Proactively find deprecated code paths
intervention Browser actively blocks problematic behavior Yes Detect violations of UX heuristics
crash Tab crash or memory exhaustion No, server-side only Surface stability issues JS cannot capture

Mironsoft

Modern browser APIs, performance, and maintainable JavaScript

JavaScript that holds up in the real browser, not just in the tutorial?

We review existing frontend code for outdated patterns, unnecessary dependencies, and performance traps, then replace them with modern, native browser APIs that mean less bundle weight and less maintenance burden.

Code Review

Systematically finding outdated patterns, unnecessary dependencies, and memory leaks.

Performance Optimization

Improving bundle size, load time, and runtime performance with modern APIs.

Modernization

Deliberately introducing native browser APIs instead of heavy libraries.

10. Summary

Reporting API: The Essentials at a Glance

Configuration

The Reporting-Endpoints header defines destination URLs, CSP references them via report-to.

Client side

ReportingObserver reads reports directly in the browser, enriched with custom context.

Strength

Captures cases like crashes that classic JS error tracking would never see.

Limit

Support varies by browser, server-side endpoints remain the more reliable base.

11. FAQ: Reporting API: The Essentials at a Glance

1What is the Reporting API?
A browser mechanism that automatically sends structured reports about events like CSP violations, deprecation warnings, or crashes to configured endpoints.
2How do you configure a report endpoint?
Via the HTTP header Reporting-Endpoints, which defines named destination URLs that can then be referenced by other headers such as the Content Security Policy.
3What is the difference from the old Report-To header?
Report-To used JSON-formatted values and has increasingly been superseded by the simpler Reporting-Endpoints format, which fulfills the same basic function.
4What does the ReportingObserver do?
It allows intercepting and evaluating reports directly in the browser via JavaScript, without waiting for a server round trip.
5Does the Reporting API also capture tab crashes?
Yes, via the crash report type, which is generated by the browser process itself since JavaScript is no longer running at that point.
6What is CSP reporting especially good for?
Testing a new or tightened Content Security Policy first in report-only mode and collecting real violations before it is actually enforced.
7Can it detect deprecated API usage?
Yes, via the deprecation report type, deprecated code paths can be proactively identified before a browser update actually removes the feature.
8Are all report types visible in the ReportingObserver?
No, crash reports for example are only retrievable server-side via the configured endpoint, not through the client-side observer.
9Do you need to consider privacy?
Yes, reports can contain sensitive information like URLs or query parameters, the endpoint should stay restricted to your own infrastructure.
10Do all browsers fully support the Reporting API?
No, Chrome and Chromium-based browsers offer the broadest feature set, Firefox and Safari support parts but not always the full ReportingObserver.