The report delivery format
The application/reports+json envelope the browser POSTs, and how it differs from the legacy application/csp-report format.
Last update:
When the browser delivers reports, it sends an HTTP POST with
Content-Type: application/reports+json and a JSON array of report objects. Every
report shares the same outer envelope; only the body changes per type. This page
is the reference for that envelope, and for the older single-object format that
report-uri still uses.
The request
Reports arrive as a POST whose body is a JSON array, not a single object,
even when there is only one report. A single delivery can batch several reports
together, and they do not have to be the same type: a CSP violation and a
deprecation can share one POST if they are queued for the same endpoint. Your
receiver should iterate the array and branch on each entry's type.
The envelope fields
Every entry in the array has the same five top-level fields. Only body differs
from one report type to the next.
| Field | Meaning |
|---|---|
type | The report category, for example csp-violation, deprecation, network-error. |
url | The document the report came from, stripped of credentials and fragment. |
user_agent | The User-Agent string of the page that generated the report. |
age | Milliseconds between when the report was generated and when it was sent, so you can correct for the batching delay and clock skew. |
body | The type-specific payload (the fields documented on each report page). |
[
{
"type": "csp-violation",
"age": 53,
"url": "https://api-next.centralcsp.com/",
"user_agent": "Mozilla/5.0 ...",
"body": {
"documentURL": "https://api-next.centralcsp.com/",
"blockedURL": "https://evil.example/script.js",
"effectiveDirective": "script-src-elem",
"disposition": "enforce",
"statusCode": 200
}
}
]Modern format vs the legacy csp-report format
The Reporting API uses camelCase body fields (documentURL, blockedURL); the legacy report-uri format uses a single object wrapped in csp-report with kebab-case fields (document-uri, blocked-uri) and Content-Type: application/csp-report. An endpoint that accepts both must branch on the Content-Type.
The legacy format predates the Reporting API and is specific to CSP. It is a single
object, not an array, it has no envelope (no type, age, or user_agent), and its
field names are kebab-case:
{
"csp-report": {
"document-uri": "https://api-next.centralcsp.com/",
"blocked-uri": "https://evil.example/script.js",
"effective-directive": "script-src-elem",
"original-policy": "default-src 'self'; report-uri /csp-reports",
"disposition": "enforce",
"status-code": 200
}
}So a receiver that supports both reads the Content-Type: application/reports+json
means the modern array, application/csp-report means the legacy object. The
csp-violation report page documents
both shapes field by field.
See also
- csp-violation report
- How the Reporting API works
- Reporting-Endpoints header
- Where browser reports go and how to receive them