reporting-api
April 10, 2026 ยท View on GitHub
Express.js middleware for the Reporting API. Automatically wires up report-to / report-uri on your existing policy headers and gives you a ready-made endpoint to collect violation, deprecation, crash, and network error reports.
Supported headers and report types
Plus Deprecation, Intervention, and Crash reports.
Backwards-compatible with CSP Level 2 report-uri for browsers that don't yet support the Reporting API.
Install
npm install reporting-api
Peer dependencies: express, zod, debug.
Quick start
import express from 'express';
import { reportingEndpoint, setupReportingHeaders } from 'reporting-api';
const app = express();
// 1. Mount the reporting endpoint
app.use('/reporting-endpoint', reportingEndpoint({
allowedOrigins: '*',
onReport(report) {
console.log(report.type, report.body);
},
}));
// 2. Set your policy headers, then let the middleware attach reporters
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy', "script-src 'self'");
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
next();
});
app.use(setupReportingHeaders('/reporting-endpoint'));
app.listen(8080);
Note
Policy headers must be set before setupReportingHeaders runs so the middleware can append report-to and report-uri directives to them.
The resulting response headers will look like this:
Reporting-Endpoints: reporter="/reporting-endpoint"
Content-Security-Policy: script-src 'self';report-uri /reporting-endpoint?disposition=enforce;report-to reporter
Cross-Origin-Opener-Policy: same-origin;report-to="reporter"
Cross-Origin-Embedder-Policy: require-corp;report-to="reporter"
API
reportingEndpoint(config)
Returns Express middleware that accepts incoming reports.
| Option | Type | Description |
|---|---|---|
onReport | (report, req) => void | Called for every valid report. |
onValidationError | (error, body, req) => void | Called when a report fails Zod validation. |
allowedOrigins | string | RegExp | Array | Enable CORS for cross-origin reports. Use '*' to allow any origin. |
ignoreBrowserExtensions | boolean | Drop CSP violations originating from browser extensions. |
ignoredDeprecationIds | string[] | Deprecation report IDs to ignore (e.g. ['AttributionReporting', 'Topics']). |
maxAge | number | Maximum report age in seconds. Older buffered reports are dropped. |
debug | boolean | Enable debug logging for the reporting-api:* namespace. |
setupReportingHeaders(url, config?)
Returns Express middleware that appends report-to / report-uri to every policy header already set on the response and adds the Reporting-Endpoints header.
| Option | Type | Default | Description |
|---|---|---|---|
reportingGroup | string | "reporter" | Reporting group name. |
enableDefaultReporters | boolean | false | Use the default group so you also receive Deprecation, Crash, and Intervention reports. |
enableNetworkErrorLogging | boolean | object | false | Add Report-To + NEL headers (Reporting API v0, required for NEL). Accepts { success_fraction, failure_fraction, include_subdomains }. |
version | string | number | โ | Appended as a ?version= query param so you can correlate reports with policy revisions. |
Report schema
Every report delivered to onReport is validated with Zod and has the shape:
{
type: 'csp-violation' | 'coop' | 'coep' | 'deprecation' | 'crash'
| 'intervention' | 'network-error' | 'permissions-policy-violation'
| 'potential-permissions-policy-violation';
body: { /* type-specific fields */ };
url: string;
age: number;
user_agent: string;
report_format: 'report-uri' | 'report-to' | 'report-to-safari';
version?: string;
}
Full type definitions are exported as Report and the individual body types (ContentSecurityPolicyReport, CrossOriginOpenerPolicyReport, etc.).
Client-side observing
Reports can also be observed in the browser via ReportingObserver:
if (typeof ReportingObserver !== 'undefined') {
new ReportingObserver((reports) => {
reports.forEach(r => console.log(r.body));
}).observe();
}
Resources
- Reporting API v1 spec (Reporting-Endpoints)
- Reporting API v0 spec (Report-To)
- Migrating from v0 to v1
- v0 vs v1 differences (Chromium)
- Permissions-Policy reporting
Notes
Permissions-Policyreports to thedefaultgroup whenreport-tois not set.- COOP and COEP require
report-tovalues wrapped in double quotes (e.g.report-to="group"). - Safari sends reports as
{ body: { ... } }instead of an array and omitsage.