# ReportingObserver, catch deprecations and CSP violations in JavaScript (/en/blog/reporting-observer-javascript)





Most of the Reporting API ships browser reports off to a server you control. The
`ReportingObserver` API does the opposite: it hands those same reports to your own
JavaScript, inside the page, the moment they fire. No response header, no endpoint, no
backend. You construct an observer, give it a callback, and the browser starts calling
you with deprecation warnings, browser interventions, and (where supported) CSP
violations as they happen. It is the in-page counterpart to endpoint reporting, and it
slots straight into a front-end error pipeline you already run.

## What it observes [#what-it-observes]

[`ReportingObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ReportingObserver)
is a constructor available in the page's own JavaScript. You point it at the report
types you care about and it delivers matching reports to your callback. It covers:

* `deprecation`, an API your page uses is slated for removal.
* `intervention`, the browser overrode something your code asked for.
* CSP violations, where the browser surfaces them through this interface.

These are the same events the browser would otherwise batch and POST to a server. The
difference is where you read them: in the page, in real time, with the full report
object in hand. The observer surfaces deprecation, intervention, and CSP violation
reports; crash reports never reach it and go only to a server endpoint. Of the three
it does surface, CSP violation delivery is the least consistent across browsers, so
confirm it in your target browsers before depending on it.

## Wire one up [#wire-one-up]

You create the observer with a callback and an options object. The callback receives a
list of reports and the observer itself. The two options that matter are `types`, the
report types to watch, and `buffered`, which replays reports that fired before your
observer existed so you do not miss early ones during page load.

```ts twoslash title="reporting-observer.ts"
// @lib: dom,esnext
// @noErrors
declare function sendToErrorPipeline(entry: unknown): void;
// ---cut---
const observer = new ReportingObserver(
  (reports, observer) => {
    for (const report of reports) {
      // report.type is "deprecation", "intervention", or "csp-violation"
      // report.body holds the type-specific fields
      sendToErrorPipeline({
        type: report.type,
        url: report.url,
        body: report.body,
      });
    }
  },
  { types: ["deprecation", "intervention"], buffered: true }
);

observer.observe();
```

Call `observe()` to start. The `buffered: true` flag is what makes this reliable: a
deprecation can fire while your bundle is still parsing, and without buffering you
would never see it. With it, those early reports are replayed into your first
callback.

## Fit it into a front-end error pipeline [#fit-it-into-a-front-end-error-pipeline]

If you already capture JavaScript errors and unhandled rejections in the browser and
ship them to a logging service, `ReportingObserver` is one more source for that same
pipeline. Treat each report like an error event: tag it with the type, attach the
source location from `report.body`, and send it through the channel you already have.

```javascript title="error-pipeline.js"
function sendToErrorPipeline(entry) {
  // reuse your existing client logger / beacon
  navigator.sendBeacon("/client-logs", JSON.stringify(entry));
}

window.addEventListener("error", (e) =>
  sendToErrorPipeline({ type: "js-error", message: e.message })
);

new ReportingObserver(
  (reports) => reports.forEach((r) =>
    sendToErrorPipeline({ type: r.type, body: r.body })
  ),
  { types: ["deprecation", "intervention"], buffered: true }
).observe();
```

Using `sendBeacon` keeps the report from being dropped when the user navigates away,
the same reason the Reporting API delivers out of band. Now a deprecation shows up in
the same dashboard as a thrown exception, with the source file and line that
triggered it.

## It complements endpoint reporting, it does not replace it [#it-complements-endpoint-reporting-it-does-not-replace-it]

`ReportingObserver` and endpoint-based reporting answer different questions, so most
teams want both.

```mermaid
flowchart LR
  A["Browser report<br/>(deprecation, intervention, CSP)"] --> B["In-page ReportingObserver<br/>your JS callback, no header"]
  A --> C["Browser queue<br/>Reporting-Endpoints header"]
  C --> D["Your server endpoint"]
```

* The observer runs only while your page is alive and only sees what this session
  produces. It is great for real-time front-end telemetry and for routing reports
  into tooling you already own.
* Endpoint reporting, declared with the
  [`Reporting-Endpoints`](/en/docs/web-security/reporting-api/headers/reporting-endpoints) header,
  keeps working when the page is gone, aggregates across all your traffic, and
  catches report types the observer does not, like crash reports. That is the
  authoritative, server-side view.

Use the observer to surface issues fast in your own front-end stack, and use endpoint
reporting as the durable record. Set up the endpoint side in
[how to set up the Reporting API](/en/blog/how-to-set-up-the-reporting-api), and read
the full catalog of report types on the
[reports reference](/en/docs/web-security/reporting-api/reports). The mechanics of the observer
itself are on the
[ReportingObserver concept page](/en/docs/web-security/reporting-api/concepts/reporting-observer).

## Send both views to one place [#send-both-views-to-one-place]

The observer gives you reports in the browser; the endpoint gives you reports from
real traffic. CentralCSP ingests every browser report type on the endpoint side, so
your `ReportingObserver` and your `Reporting-Endpoints` configuration can
[feed the same reporting view](/platform/monitoring), with deprecations,
interventions, and CSP violations grouped and trended instead of scattered across a
console and a log file. You get the real-time front-end signal and the durable,
cross-traffic record without building two pipelines.

<img alt="The report explorer with the type selector open over the table" src="__img0" width="1359" height="645" />

## Next steps [#next-steps]

* Set up the endpoint side: [how to set up the Reporting API](/en/blog/how-to-set-up-the-reporting-api).
* Browse [every report type](/en/docs/web-security/reporting-api/reports) and what each tells you.
* Read the [ReportingObserver concept page](/en/docs/web-security/reporting-api/concepts/reporting-observer).

[Collect every browser report in one place](/register).

## Sources [#sources]

* [ReportingObserver on MDN](https://developer.mozilla.org/en-US/docs/Web/API/ReportingObserver)
* [Reporting API on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Reporting_API)
* [Reporting API specification (W3C)](https://www.w3.org/TR/reporting-1/)

## Related [#related]

* [How to set up the browser Reporting API](/en/blog/how-to-set-up-the-reporting-api)
* [Deprecation and intervention reports](/en/blog/deprecation-intervention-reports)
* [What is NEL, network error logging from the browser](/en/blog/what-is-nel-network-error-logging)
