Monitor your web application with the Reporting API

Use the Reporting API to monitor security violations, deprecated API calls, and more.

Maud Nalpas
Maud Nalpas

Caution:

This is an API guide with detailed usage examples for theReportingAPI (v1), which uses theReporting-Endpoints header.

If you're using the legacy Reporting API (Report-To header), read aboutAPI migration instead.

Are you looking forNetwork Error Logging documentation? Head over to Network Error logging instead.

Some errors only occur in production. You won't see them locally or duringdevelopment becausereal users,real networks, andreal deviceschange the game. The Reporting API helps catch some of these errors—suchas security violations or deprecated and soon-to-be-deprecated APIcalls across your site, and transmits them to an endpoint you'vespecified.

It lets you declare what you'd like to monitor via HTTP headers, and isoperatedby the browser.

Setting up the Reporting API gives you peace of mind that when users experiencethese types of errors, you'll know, so you can fix them.

This post covers what this API can do and how to use it. Let's dive in!

Demo and code

See the Reporting API in action starting fromChrome 96 and newer (ChromeBeta or Canary, as of October 2021).

Try it:
  • Demo reporting endpoint.This page receives and displays reports. Review thecode.
  • Demo report generation.This page uses the new Reporting API with theReporting-Endpoints header. It also intentionally violates itsown policies, uses deprecated APIs, and does other bad things in order togenerate reports.Reporting-Endpoints on this page is set tosend reports to the demo reporting endpoint mentioned above. Review thecode.

Overview

Diagram summarizing the steps below, from report generation to report access by the developer
How reports are generated and sent.

Let's assume that your site,site.example, has a Content-Security-Policy and a Document-Policy. Don't know what these do? That's okay, you'll still beable to understand this example.

You decide to monitor your site in order to know when these policies are violated, but also becauseyou want to keep an eye on deprecated or soon-to-be-deprecated APIs your codebase may be using.

To do so, you configure aReporting-Endpoints header, and map these endpointnames via thereport-to directive in your policies where needed.

Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"
#Content-Security-PolicyviolationsandDocument-Policyviolations#willbesenttomain-endpointContent-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;Document-Policy: document-write=?0; report-to=main-endpoint;#Deprecationreportsdon'tneedanexplicitendpointbecause#thesereportsarealwayssenttothe`default`endpoint

Something unforeseen happens, and these policies get violated for some of yourusers.

Example violations

index.html

<script src="script.js"></script><!-- CSP VIOLATION: Try to load a script that's forbidden as per the Content-Security-Policy --><script src="https://example.com/script.js"></script>

script.js, loaded byindex.html

// DOCUMENT-POLICY VIOLATION: Attempt to use document.write despite the document policytry{document.write('<h1>hi</h1>');}catch(e){console.log(e);}// DEPRECATION: Call a deprecated APIconstwebkitStorageInfo=window.webkitStorageInfo;

The browser generates a CSP violation report, a Document-Policy violation report, and a Deprecationreport that capture these issues.

With a short delay—up to a minute—the browser then sends the reports to theendpoint that was configured for this violation type. The reports are sentout-of-band by thebrowser itself (not by your server nor by your site).

The endpoint(s) receive(s) these reports.

You can now access the reports on these endpoints and monitor what went wrong.You're ready to start troubleshooting the problem that's affecting your users.

Example report

{"age":2,"body":{"blockedURL":"https://site2.example/script.js","disposition":"enforce","documentURL":"https://site.example","effectiveDirective":"script-src-elem","originalPolicy":"script-src 'self'; object-src 'none'; report-to main-endpoint;","referrer":"https://site.example","sample":"","statusCode":200},"type":"csp-violation","url":"https://site.example","user_agent":"Mozilla/5.0... Chrome/92.0.4504.0"}

Use cases and report types

The Reporting API can be configured to help you monitor many types of interesting warnings or issuesthat happen throughout your site:

Caution:Network Error Logging isn't listed because it isn'tsupported in the new version of the API. Check themigrationguide for details.
Report typeExample of a situation where a report would be generated
CSP violation (Level 3 only)You've set aContent-Security-Policy (CSP) on one of your pages, but the page is trying to load a script that's not allowed by your CSP.
COOP violationYou've set aCross-Origin-Opener-Policy on a page, but a cross-origin window is trying to interact directly with the document.
COEP violationYou've set aCross-Origin-Embedder-Policy on a page, but the document includes a cross-origin iframe that has not opted into being loaded by cross-origin documents.
Document Policy violationThe page has a document policy that prevents usage ofdocument.write, but a script tries to calldocument.write.
Permissions policy violationThe page has a permissions policy that prevents microphone usage, and a script that requests audio input.
Deprecation warningThe page is using an API that is deprecated or will be deprecated; it calls it directly or via a top-level third-party script.
InterventionThe page is trying to do something that the browser decides not to honor, for security, performance or user experience reasons. Example in Chrome: the page usesdocument.write on slow networks or callsnavigator.vibrate in a cross-origin frame that the user hasn't interacted with yet.
CrashThe browser crashes while your site is open.

Reports

What do reports look like?

The browser sends reports to the endpoint you've configured. It sends requests that look as follows:

POSTContent-Type: application/reports+json

The payload of these requests is a list of reports.

Example list of reports

[{"age":420,"body":{"columnNumber":12,"disposition":"enforce","lineNumber":11,"message":"Document policy violation: document-write is not allowed in this document.","policyId":"document-write","sourceFile":"https://site.example/script.js"},"type":"document-policy-violation","url":"https://site.example/","user_agent":"Mozilla/5.0... Chrome/92.0.4504.0"},{"age":510,"body":{"blockedURL":"https://site.example/img.jpg","destination":"image","disposition":"enforce","type":"corp"},"type":"coep","url":"https://dummy.example/","user_agent":"Mozilla/5.0... Chrome/92.0.4504.0"}]

Here's the data you can find in each of these reports:

FieldDescription
ageThe number of milliseconds between the report's timestamp and the current time.
bodyThe actual report data, serialized into a JSON string. The fields contained in a report'sbody are determined by the report'stype.⚠️ Reports of different types have different bodies. To see the exact body of each report type, check out thedemo reporting endpoint and follow the instructions to generate example reports.
typeA report type, for examplecsp-violation orcoep.
urlThe address of the document or worker from which the report was generated. Sensitive data such as username, password, and fragment arestripped from this URL.
user_agentTheUser-Agent header of the request from which the report was generated.

Credentialed reports

Reporting endpoints that have thesame origin as the page that generates the report receive the credentials(cookies) in the requests that contain the reports.

Credentials may give useful additional context about the report; forexample, whether a given user’s account is triggering errors consistently, or if a certain sequenceof actions taken on other pages is triggering a report on this page.

Note:Cross-origin endpointsdon't receive credentials. This is a security measure and can't be changed.

When and how does the browser send reports?

Reports are delivered out-of-band from your site: the browser controls whenthey're sent to the configured endpoint(s). There's also no way to control whenthe browser sends reports; it captures, queues, and sends them automatically ata suitable time.

This means that there's little to no performance concern when using the Reporting API.

Reports are sent with a delay—up to a minute—to increase the chances to send reports in batches.This saves bandwidth to be respectful to the user's network connection, which is especiallyimportant on mobile. The browser can also delay delivery if it's busy processing higher prioritywork, or if the user is on a slow and/or congested network at the time.

Note: When you're debugging locally, you can turn off this delay for convenience.See how.

Third-party and first-party issues

Reports that are generated due to violations or deprecations happeningon your page will be sentto the endpoint(s) you've configured. This includes violations committed bythird-party scriptsrunning on your page.

Violations or deprecations that happenedin a cross-origin iframe embedded in your page willnot be reported to your endpoint(s) (at least not by default). An iframe could set up its ownreporting and even report to your site's—that is, the first-party's—reporting service; but that's upto the framed site. Also note that most reports are generated only if a page's policy is violated,and that your page's policies and the iframe's policies are different.

Key point: In Chrome DevTools, you'll see a console error or warning pop up for violations that are committedby third-party scriptsand cross-origin iframes. Not all of these will translate into reports beingsent to your endpoint: the formers will, the latters won't.

Example with deprecations

If the Reporting-Endpoints header is set up on your page: deprecated API called by third-party scripts running on your page will be reported to your endpoint. Deprecated API called by an iframe embedded in your page will not be reported to your endpoint. A deprecation report will be generated only if the iframe server has set up Reporting-Endpoints, and this report will be sent to whichever endpoint the iframe's server has set up.
If the Reporting-Endpoints header is set up on your page: deprecated API called by third-party scripts running on your page will be reported to your endpoint. Deprecated API called by an iframe embedded in your page will not be reported to your endpoint. A deprecation report will be generated only if the iframe server has set up Reporting-Endpoints, and this report will be sent to whichever endpoint the iframe's server has set up.

Browser support

The table below sums up browser support for theReporting API v1, that is with theReporting-Endpoints header. Browser support for the Reporting API v0 (Report-To header) is thesame, except for one report type: Network Error Logging isn't supported in the new Reporting API.Read themigration guide for details.

Report typeChromeChrome iOSSafariFirefoxEdge
CSP violation (Level 3 only)*✔ Yes✔ Yes✔ Yes✘ No✔ Yes
Network Error Logging✘ No✘ No✘ No✘ No✘ No
COOP/COEP violation✔ Yes✘ No✔ Yes✘ No✔ Yes
All other types: Document Policy violation, Deprecation, Intervention, Crash✔ Yes✘ No✘ No✘ No✔ Yes
Caution:

Browser support for CSP reporting is different from other reporting types, because CSP has been around for some time. CSP reports can be generated via:

  • The legacyreport-uri directive that doesn't rely on the Reporting API.
  • The newerreport-to directive that relies on the Reporting API (and theReporting-To or the newerReporting-Endpoints headers).

This table only summarizes support forreport-to with the newReporting-Endpoints header. Read theCSP reporting migration tips if you're looking to migrate toReporting-Endpoints.

Using the Reporting API

Decide where reports should be sent

You have two options:

  • Send reports to an existing report collector service.
  • Send reports to a reporting collector you build and operate yourself.

Option 1: Use an existing report collector service

Some examples of report collector services are:

If you know of other solutions,open an issue to let us know, and we'll update this post!

Beside pricing, consider the following points when selecting a report collector: 🧐

  • Does this collector support all report types? For example, not all reporting endpoint solutionssupport COOP/COEP reports.
  • Are you comfortable sharing any of your application's URLs with a third-party report collector?Even if the browser strips sensitive information from these URLs, sensitive informationmay get leaked this way. If this sounds too risky foryour application, operate your own reporting endpoint.

Option 2: Build and operate your own report collector

Building your own server that receives reports isn't that trivial. To get started, you can fork ourlightweight boilerplate. It's built with Express and can receive and display reports.

Caution: Don't use it as-in in production, but feel free to use it for a quickprototype. Make sure to fork it before using it, so that nobody you don't trust gets to see reportsgenerated by your page.
  1. Head over to theboilerplate report collector.

  2. ClickRemix to Edit to make the project editable.

  3. You now have your clone! You can customize it for your own purposes.

If you're not using the boilerplate and are building your own server from scratch:

  • Check forPOST requests with aContent-Type ofapplication/reports+json to recognize reportsrequests sent by the browser to your endpoint.
  • If your endpoint lives on a different origin than your site, ensure it supportsCORS preflight requests.
Key point: Make sure your endpoint supportsCORS preflightrequests.

Option 3: Combine Option 1 and 2

You may want to let a specific provider take care of some types of reports, but have an in-housesolution for others.

In this case, set multiple endpoints as follows:

Reporting-Endpoints: endpoint-1="https://reports-collector.example", endpoint-2="https://my-custom-endpoint.example"

Configure theReporting-Endpoints header

Set aReporting-Endpoints response header. Its value must be one or a series of comma-separatedkey-value pairs:

Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"

If you're migrating from the legacy Reporting API to the new Reporting API, it may make sense tosetbothReporting-Endpoints andReport-To. See details in themigration guide. In particular, if you're using reporting forContent-Security-Policy violations via thereport-uri directive only, check themigration steps for CSP reporting.

Reporting-Endpoints: main-endpoint="https://reports.example/main", default="https://reports.example/default"Report-To: ...

Keys (endpoint names)

Each key can be a name of your choice, such asmain-endpoint orendpoint-1.You can decide to set different named endpoints for different reporttypes—for example,my-coop-endpoint,my-csp-endpoint. With this, youcan route reports to different endpoints depending on their type.

If you want to receiveintervention,deprecation and/orcrashreports, set an endpoint nameddefault.

If theReporting-Endpoints header defines nodefault endpoint, reports of this type willnot be sent (although they will be generated).

Key point: Despite its name,default isnot a fallbackendpoint. For example, if you set upreport-to my-endpoint forDocument-Policy and omit to definemy-endpoint inReporting-Endpoints,Document-Policy violationsreports will be generated but willnot be sent because thebrowser doesn't know where to send them to.

Values (URLs)

Each value is a URL of your choice, where the reports will be sent to. The URLto set here depends on what you decided in Step 1.

An endpoint URL:

Examples

Reporting-Endpoints: my-coop-endpoint="https://reports.example/coop", my-csp-endpoint="https://reports.example/csp", default="https://reports.example/default"

You can then use each named endpoint in the appropriate policy, or use onesingle endpoint across all policies.

Where to set the header?

In the new Reporting API—the one that is covered in thispost— reports are scoped todocuments. This means that for one givenorigin, different documents, such assite.example/page1 andsite.example/page2, can send reports to different endpoints.

To receive report for violations or deprecations take place on any page of yoursite, set the header as a middleware on all responses.

Here's an example in Express:

constREPORTING_ENDPOINT_BASE='https://report.example';constREPORTING_ENDPOINT_MAIN=`${REPORTING_ENDPOINT_BASE}/main`;constREPORTING_ENDPOINT_DEFAULT=`${REPORTING_ENDPOINT_BASE}/default`;app.use(function(request,response,next){// Set up the Reporting APIresponse.set('Reporting-Endpoints',`main-endpoint="${REPORTING_ENDPOINT_MAIN}", default="${REPORTING_ENDPOINT_DEFAULT}"`,);next();});
Note: This is different from the legacy Reporting API (Report-To header), where youcould set an "ambient" endpoint for one page, and automatically get reports forany page on the same origin. If you're migrating from the legacy Reporting APIto the new Reporting API, check themigration guide.

Edit your policies

Now that theReporting-Endpoints header is configured, add areport-todirective to each policy header for which you wish to receive violationreports. The value ofreport-to should be one of the named endpoints you'veconfigured.

You can use the multiple endpoint for multiple policies, or use differentendpoints across policies.

For each policy, the value of report-to should be one of the named endpoints you've configured.

report-to is not needed fordeprecation,intervention andcrashreports. These reports aren't bound to any policy. They're generated as long asadefault endpoint is set up and are sent to thisdefault endpoint.

Example

#Content-Security-PolicyviolationsandDocument-Policyviolations#willbesenttomain-endpointContent-Security-Policy: script-src 'self'; object-src 'none'; report-to main-endpoint;Document-Policy: document-write=?0;report-to=main-endpoint;#Deprecationreportsdon'tneedanexplicitendpointbecause#thesereportsarealwayssenttothedefaultendpoint
Warning: Getting thereport-to syntax right can be tricky, because not all policies usethe same header structure. Depending on the policy, the right syntax may bereport-to=main-endpoint orreport-to main-endpoint. Head over to thedemo for code examples.

Example code

To see all this in context, below is an example Node server that uses Expressand brings together all the pieces discussed in this article. It shows how toconfigure reporting for several different report types and displays the results.

Debug your reporting setup

Intentionally generate reports

When setting up the Reporting API, you'll likely need to intentionally violateyour policies in order to check if reports are generated and sent as expected.To see example code that violates policies and does other bad things that willgenerate reports of all types, check out thedemo.

Save time

Reports may be sent with a delay—about a minute, which is along timewhen debugging. 😴 Luckily, when debugging in Chrome, you can use the flag--short-reporting-delay to receive reports as soon as they're generated.

Run this command in your terminal to turn on this flag:

YOUR_PATH/TO/EXECUTABLE/Chrome--short-reporting-delay
Key point: This flag is not available via the Chrome UI, it's a command line flag only.Learnhow to run Chromium withflags.

Use DevTools

In Chrome, use DevTools to see the reports that have been sent or will be sent.

As of October 2021, this feature is experimental. To use it, follow these steps:

  1. Use Chrome version96 and newer (check by typingchrome://version in your browser)
  2. Type or pastechrome://flags/#enable-experimental-web-platform-features in Chrome's URL bar.
  3. ClickEnabled.
  4. Restart your browser.
  5. Open Chrome DevTools.
  6. In Chrome DevTools, open the Settings. Under Experiments, clickEnable Reporting API panel inthe Application panel.
  7. Reload DevTools.
  8. Reload your page. Reports generated by the page DevTools is open in will belisted in Chrome DevTools'Application panel, underReporting API.
Screenshot of DevTools listing the reports
Chrome DevTools displays the reports generated on your page and their status.

Report status

TheStatus column tells you if a report has been successfully sent.

StatusDescription
SuccessThe browser has sent the report and the endpoint replied with a success code (200 or another success response code2xx).
PendingThe browser is currently making an attempt to send the report.
QueuedThe report has been generated and the browser is not currently trying to send it. A report appears asQueued in one of these two cases:
  • The report is new and the browser is waiting to see if more reports arrive before trying to send it.
  • The report is not new; the browser has already tried to send this report and has failed, and is waiting before trying again.
MarkedForRemovalAfter retrying for a while (Queued), the browser has stopped trying to send the report and will soon remove it from its list of reports to send.

Reports are removed after a while, whether or not they're successfully sent.

Key point: TheQueued status isn't always informative, because it doesn't precisely indicate whether sending has failed or has not been attempted yet. Usingshort reporting delays helps: a report that remainsQueued in that case likely indicates that sending is failing.

Troubleshooting

Are reports not generated or not sent as expected to your endpoint?Here are a few tips to troubleshoot this.

Reports are not generated

Reports that show up in DevTools have been correctly generated.If the report you expect doesnot show up in this list:

  • Checkreport-to in your policies. If this is misconfigured, areport won't be generated. Head over toEdit your policies tofix this. An additional way to troubleshoot this is to check the DevTools console in Chrome: if anerror pops up in the console for the violation you expected, this means your policy is probablyproperly configured.
  • Keep in mind that only the reports that were generated for the document DevTools is open in willshow up in this list. One example: if your sitesite1.example embeds an iframesite2.examplethat violates a policy and hence generates a report, this report will show up in DevTools only if you open theiframe in its own window and open DevTools for that window.

Reports are generated but not sent or not received

What if you can see a report in DevTools, but your endpoint doesn't receive it?

Key point: Because the report is sent out-of-band by the browser itself and not by acertain site, thePOST requests containing the reports are not displayed intheNetwork panel of your Developer Tools.
  • Make sure to useshort delays. Maybe the reason you can't see a report is because ithasn't been sent yet!
  • Check yourReporting-Endpoints header configuration. If there's an issue with it, a report thathas been generated correctly will not be sent. In DevTools, the report's status will remainQueued (it might jump toPending, and then quickly back toQueued when a delivery attempt ismade) in this case. Some common mistakes that may cause this:

  • The endpoint is used but not configured. Example:

Code with a mistake
 Document-Policy: document-write=?0;report-to=endpoint-1; Reporting-Endpoints: default="https://reports.example/default"

Document-Policy violation reports should be sent toendpoint-1, but this endpoint name isn't configured inReporting-Endpoints.

  • Thedefault endpoint is missing. Some reports types, such as deprecation and interventionreports, will only be sent to the endpoint nameddefault. Read more inConfigure the Reporting-Endpoints header.

  • Look for issues in your policy headers syntax, such as missing quotes.See details.

  • Check that your endpoint can handle incoming requests.

    • Make sure that your endpoint support CORS preflight requests. If it doesn't, it can't receive reports.

    • Test your endpoint's behavior. To do so, instead of generatingreports manually, you can emulate the browser by sending to your endpoint requests thatlook likewhat the browser would send. Run the following:

    curl--header"Content-Type: application/reports+json"\--requestPOST\--data'[{"age":420,"body":{"columnNumber":12,"disposition":"enforce","lineNumber":11,"message":"Document policy violation: document-write is not allowed in this document.","policyId":"document-write","sourceFile":"https://dummy.example/script.js"},"type":"document-policy-violation","url":"https://dummy.example/","user_agent":"xxx"},{"age":510,"body":{"blockedURL":"https://dummy.example/img.jpg","destination":"image","disposition":"enforce","type":"corp"},"type":"coep","url":"https://dummy.example/","user_agent":"xxx"}]'\YOUR_ENDPOINT

    Your endpoint should respond with a success code (200 or another success response code2xx). If it doesn't,there's an issue with its configuration.

Related reporting mechanisms

Report-Only

-Report-Only policy headers and theReporting-Endpoints work together.

Endpoints configured inReporting-Endpoints and specified in thereport-to field ofContent-Security-Policy,Cross-Origin-Embedder-Policy andCross-Origin-Opener-Policy, will receive reports when these policies are violated.

Endpoints configured inReporting-Endpoints can also be specified in thereport-to field ofContent-Security-Policy-Report-Only,Cross-Origin-Embedder-Policy-Report-Only andCross-Origin-Opener-Policy-Report-Only.They'll also receive reports when these policies are violated.

While reports are sent in both cases,-Report-Only headers do not enforce thepolicies: nothing will break or actually get blocked, but you will receivereports of whatwould have broken or been blocked.

Note: If you're using a-Report-Only header and have configured your reporting endpoints via the legacy headerReport-To, migrate toReporting-Endpoints if you can. Read more in themigration guide.

ReportingObserver

TheReportingObserver JavaScript API can help youobserve client-side warnings.

ReportingObserver and theReporting-Endpoints header generate reports thatlook the same, but they enable slightly different uses cases.

UseReportingObserver if:

  • You only want to monitor deprecations and/or browser interventions.ReportingObserver surfacesclient-side warnings such as deprecationsand browser interventions, but unlikeReporting-Endpoints, it doesn'tcapture any other types of reports such as CSP or COOP/COEP violations.
  • You need to react to these violations in real-time.ReportingObserver makesit possible toattach a callback to a violation event.
  • You want to attach additional information to a report to aid in debugging,via the customcallback.

Another difference is thatReportingObserver is configured only client-side:you can use it even if you have no control over server-side headers and can'tsetReporting-Endpoints.

Further reading

Hero image byNine Koepfer / @enka80 onUnsplash, edited. Many thanks to Ian Clelland, Eiji Kitamura and Milica Mihajlija for their reviews and suggestions on this article.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2021-10-19 UTC.