Find deprecated APIs in your production apps.


Eric Bidelman [X](https://twitter.com/ebidel) [GitHub](https://github.com/ebidel) [Homepage](http://ericbidelman.com/)

<br />

`ReportingObserver` lets you know when your site uses a deprecated API or runs
into a [browser intervention](https://www.chromestatus.com/features#intervention). The basic functionality originally
landed in Chrome 69. As of Chrome 84, it can be used in workers.

    const observer = new ReportingObserver((reports, observer) => {
      for (const report of reports) {
        console.log(report.type, report.url, report.body);
      }
    }, {buffered: true});

    observer.observe();

Use the callback to send reports to a backend or analytics provider for
analysis.

Why is that useful? Until this API, deprecation and intervention warnings were
only available in DevTools as Console messages. Interventions, in particular,
are only triggered by various real-world constraints like device and network
conditions. Thus, you may never even see these messages when developing/testing
a site locally. `ReportingObserver` provides a solution to this problem. When
users experience potential issues in the wild, web developers can be notified
about them.

## Background

A while back, I wrote a blog post ([Observing your web app](https://ericbidelman.tumblr.com/post/149032341876/observing-your-web-app))
because I found it fascinating how many APIs there are for monitoring the
"stuff" that happens in a web app. For example, there are APIs that can observe
information about the DOM:
[`ResizeObserver`](https://developer.mozilla.org/docs/Web/API/ResizeObserver),
[`IntersectionObserver`](https://developer.mozilla.org/docs/Web/API/IntersectionObserver),
[`MutationObserver`](https://developer.mozilla.org/docs/Web/API/MutationObserver).
[`PerformanceObserver`](https://developer.mozilla.org/docs/Web/API/PerformanceObserver)
captures performance measurements. And methods like
[`window.onerror`](https://developer.mozilla.org/docs/Web/API/GlobalEventHandlers/onerror)
and
[`window.onunhandledrejection`](https://developer.mozilla.org/docs/Web/API/WindowEventHandlers/onunhandledrejection)
even let us know when something goes wrong.

However, there are other types of warnings which are not captured by the
existing APIs. When your site uses a deprecated API or runs up against a
[browser intervention](https://www.chromestatus.com/features#intervention), DevTools is the first to tell you about
them:
![DevTools Console warnings for deprecations and interventions.](https://developer.chrome.com/static/docs/capabilities/web-apis/reporting-observer/image/devtools-console-warnings-7e65d798d802f.png) Browser-initiated warnings in the DevTools Console.

One would naturally think `window.onerror` captures these warnings. It does not.
That's because `window.onerror` does not fire for warnings generated directly by
the user agent itself. It fires for runtime errors (JavaScript exceptions and
syntax errors) caused by code execution.

`ReportingObserver` picks up the slack. It provides a programmatic way to be
notified about browser-issued warnings such as [deprecations](https://www.chromestatus.com/features#intervention) and
[interventions](https://www.chromestatus.com/features#intervention). You can use it as a reporting tool and lose less
sleep wondering if users are hitting unexpected issues on your live site.

> [!IMPORTANT]
> **Key term:** `ReportingObserver` is part of a larger spec, the [Reporting
> API](https://developer.chrome.com/docs/capabilities/web-apis/reporting-api), which provides a common way to send these different reports to a back end. The Reporting API is a generic framework to specify a set of server endpoints to report issues to.

## The API

`ReportingObserver` is not unlike the other `Observer` APIs such as
`IntersectionObserver` and `ResizeObserver`. You give it a callback; it gives
you information. The information that the callback receives is a list of issues
that the page caused:

    const observer = new ReportingObserver((reports, observer) => {
      for (const report of reports) {
        // → report.type === 'deprecation'
        // → report.url === 'https://reporting-observer-api-demo.glitch.me'
        // → report.body.id === 'XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload'
        // → report.body.message === 'Synchronous XMLHttpRequest is deprecated...'
        // → report.body.lineNumber === 11
        // → report.body.columnNumber === 22
        // → report.body.sourceFile === 'https://reporting-observer-api-demo.glitch.me'
        // → report.body.anticipatedRemoval === <JS_DATE_STR> or null
      }
    });

    observer.observe();

### Filtered reports

Reports can be pre-filtered to only observe certain report types. Right now,
there are two report types: `'deprecation'` and `'intervention'`.

    const observer = new ReportingObserver((reports, observer) => {
      ...
    }, {types: ['deprecation']});

### Buffered reports

Use the `buffered: true` option when you want to see the reports that were
generated before the observer instance was created:

    const observer = new ReportingObserver((reports, observer) => {
      ...
    }, {types: ['intervention'], buffered: true});

This option is great for situations like lazy-loading a library that uses a
`ReportingObserver`. The observer gets added late, but you don't miss out on
anything that happened earlier in the page load.

### Stop observing

Stop observing using the `disconnect()` method:

    observer.disconnect();

## Examples

### Report browser interventions to an analytics provider

    const observer = new ReportingObserver((reports, observer) => {
      for (const report of reports) {
        sendReportToAnalytics(JSON.stringify(report.body));
      }
    }, {types: ['intervention'], buffered: true});

    observer.observe();

### Be notified when APIs are going to be removed

    const observer = new ReportingObserver((reports, observer) => {
      for (const report of reports) {
        if (report.type === 'deprecation') {
          sendToBackend(`Using a deprecated API in ${report.body.sourceFile} which will be
                         removed on ${report.body.anticipatedRemoval}. Info: ${report.body.message}`);
        }
      }
    });

    observer.observe();

## Conclusion

`ReportingObserver` gives you an additional way for discovering and monitoring
potential issues in your web app. It's even a useful tool for understanding the
health of your code base (or lack thereof). Send reports to a backend, know
about the real-world issues, update code, profit!

## Future work

In the future, my hope is that `ReportingObserver` becomes the de facto API for
catching all types of issues in JavaScript. Imagine one API to catch everything
that goes wrong in your app:

- [Browser interventions](https://www.chromestatus.com/features#intervention)
- Deprecations
- [Feature Policy](https://developer.chrome.com/blog/feature-policy) violations. See [Chromium Issue #867471](https://crbug.com/867471).
- JS exceptions and errors (currently serviced by `window.onerror`).
- Unhandled JS promise rejections (currently serviced by `window.onunhandledrejection`)

**Additional resources**:

- [W3c spec](https://w3c.github.io/reporting/#observers)
- [chromestatus.com entry](https://www.chromestatus.com/feature/4691191559880704)

[Hero image](https://unsplash.com/photos/6SyrBaRjLJ4) by
[Sieuwert Otterloo](https://unsplash.com/@sieuwert)
on [Unsplash](https://unsplash.com).