Crash Reports
Configure crash reporting to detect when browser tabs crash, run out of memory, or become unresponsive — failures that destroy your JavaScript environment before any error handler can run.
New to crash reporting? Read our Crash Reports overview to understand the benefits before diving into configuration.
What are Crash Reports?
Crash reports are notifications that browsers send when a tab or page fails catastrophically. Unlike JavaScript
errors (which your error tracking SDK can catch), crashes destroy the entire JavaScript environment — no
window.onerror, no unhandledrejection, no SDK can run code that no longer exists.
When a tab crashes, the browser itself generates a report and delivers it out-of-band — typically on the next successful page load, or even from a different tab. This is the only way to get evidence that a user's session ended in failure rather than by choice.
Each crash report includes a reason field indicating what type of crash occurred (like oom
for out-of-memory or unresponsive for killed tabs), along with metadata about the document's visibility
state at crash time.
Specification
- WICG Crash Reporting — Official specification
- Chrome Reporting API documentation — Implementation guide
- Reporting API Demos: Crash — Interactive testing tool
Browser Support
Crash reporting is supported in Chromium-based browsers starting from version 96 (October 2021). Firefox and Safari do not currently support crash reporting.
| Browser | Support | Notes |
|---|---|---|
| Chrome | 96+ | Full support |
| Edge | 96+ | Full support |
| Opera | 82+ | Full support |
| Firefox | — | Not supported |
| Safari | — | Not supported |
Why Monitor Crash Reports?
Crash reports reveal failures that are completely invisible to traditional monitoring:
- The blind spot in error tracking — Your JavaScript error SDK can't report crashes because it's destroyed along with everything else. Crash reports survive because the browser itself sends them.
- Silent user churn — Users who experience crashes often just leave. They don't report the issue — they assume something's wrong on their end or simply give up. You see a session end but have no idea it ended in failure.
- SPA memory pressure — Single-page applications are especially vulnerable. Heavy state management, data visualization, and long sessions can push against browser memory limits (typically ~2GB per tab on desktop).
- Release correlation — Correlate crash spikes with deployments to identify stability regressions before they affect more users.
- Production-only visibility — Memory leaks and performance issues often only manifest in production with real user data and session lengths that local testing doesn't replicate.
Who Benefits
- SRE teams — Monitor application stability and correlate crashes with releases
- Frontend architects — Identify memory-intensive features that push browsers to their limits
- Product managers — Understand when user sessions end due to crashes vs. normal abandonment
- Performance engineers — Track unresponsive tab kills alongside performance metrics
When to Enable
Crash reporting is recommended for all production websites, but it's essential for applications with these characteristics:
- Single-page applications (SPAs) — Long-running sessions accumulate memory
- Data-heavy dashboards — Large datasets and visualizations stress memory limits
- Collaborative editors — Real-time sync and undo history consume memory
- Media applications — Video editing, image processing, and WebGL push GPU and memory
The report volume is typically low (crashes are relatively rare events), but each report represents a user who had a seriously degraded experience.
How to Configure
crash-reporting endpoint if defined, or your
default endpoint otherwise. There's no additional header to configure beyond
Reporting-Endpoints.
Step 1: Set Up the Reporting Endpoint
Define where browsers should send crash reports using the Reporting-Endpoints header:
Reporting-Endpoints: default="https://reporting-api.app/browser-reports/YOUR-ENDPOINT-UUID"
Replace YOUR-ENDPOINT-UUID with your application's unique endpoint from the
Reporting API App dashboard.
Optional: Dedicated Crash Endpoint
If you want crash reports to go to a different endpoint than other report types, you can define a dedicated
crash-reporting endpoint:
Reporting-Endpoints: default="https://reporting-api.app/browser-reports/YOUR-UUID", crash-reporting="https://reporting-api.app/browser-reports/YOUR-CRASH-UUID"
Crash reports will be sent to crash-reporting if defined, otherwise to default.
Step 2: That's It!
There's no additional configuration required. Once the Reporting-Endpoints header is in place, browsers
will automatically send crash reports when tabs crash, run out of memory, or become unresponsive.
Why so simple? Crash reporting is automatic — you can't opt into specific crash types or set thresholds. The browser decides when a crash occurs and reports it. Your only configuration is where to send the reports.
Step 3: Monitor Reports
After deploying the header, crash reports will flow in when crashes occur. Monitor incoming reports for:
- OOM crashes — Out-of-memory failures indicating memory leaks or excessive usage
- Unresponsive crashes — Tabs killed due to being unresponsive (infinite loops, heavy computation)
- Crash rate trends — Spikes after deployments may indicate stability regressions
Step 4: Set Up Integrations
Route crash reports to your existing tools for alerting and analysis:
- AppSignal integration — Track crashes alongside application errors
- Webhook integration — Send reports to Slack, PagerDuty, or custom endpoints
- Google Chat integration — Post alerts to team chat spaces
See the Integrations documentation for setup instructions.
Understanding Crash Reports
When a browser crashes, it generates a JSON report explaining what happened. Understanding these fields helps you investigate and address the root cause.
Report Fields
| Field | Description |
|---|---|
reason |
Classification of the crash type: oom (out-of-memory) or unresponsive (tab killed).
May be omitted if unknown.
|
stack |
JavaScript call stack at crash time (only for unresponsive crashes when enabled via
Document-Policy). Same format as Error.prototype.stack.
|
is_top_level |
Boolean indicating whether the crashed document was the top-level page (true) or an iframe (false). |
visibility_state |
Document visibility at crash time: visible or hidden. Helps distinguish active vs.
background tab crashes.
|
Example Report
{
"type": "crash",
"age": 42,
"url": "https://example.com/dashboard",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"body": {
"reason": "oom"
}
}
{
"type": "crash",
"age": 0,
"url": "https://example.com/editor",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"body": {
"reason": "unresponsive",
"stack": " at processData (https://example.com/js/app.js:1234:56)\n at updateView (https://example.com/js/app.js:789:12)"
}
}
Crash Types
Browsers report two standardized crash reasons:
| Reason | Cause | Common Triggers |
|---|---|---|
| oom | Page ran out of memory | Memory leaks, large data structures, canvas/WebGL, unbounded caches |
| unresponsive | Tab killed due to being unresponsive | Infinite loops, blocking operations, heavy computation on main thread |
Out-of-Memory (OOM) Crashes
OOM crashes occur when your application exceeds the browser's per-tab memory limit (typically around 2GB on desktop, less on mobile). Research shows:
- OOM errors account for roughly 10% of all browser crashes
- Studies of popular SPAs found that 10 out of 10 had memory leaks
- Memory issues often only manifest with real user data and session lengths
Common causes include:
- Memory leaks — DOM nodes retained after removal, closure scope leaks, event listener accumulation
- Large data structures — Unbounded arrays, large object graphs, excessive caching
- Canvas and WebGL — High-resolution images, video frames, 3D rendering
- Growing undo history — Collaborative editors storing every change
Unresponsive Tab Crashes
Unresponsive crashes occur when the browser kills a tab that hasn't responded for too long. The browser protects users from pages that freeze their computer.
Common causes include:
- Infinite loops —
while(true)or recursive calls without base cases - Synchronous heavy computation — Parsing large JSON, complex algorithms on main thread
- Blocking I/O — Synchronous XHR (deprecated but still used in legacy code)
- Deadlocks — Waiting for resources that will never become available
unresponsive crashes, you can enable JavaScript call stack capture by adding the
Document-Policy: include-js-call-stacks-in-crash-reports header. This provides visibility into exactly
where the code was stuck.
Enabling Stack Traces
By default, crash reports don't include JavaScript stack traces. For unresponsive crashes, you can
enable stack capture using the Document-Policy header:
Document-Policy: include-js-call-stacks-in-crash-reports Reporting-Endpoints: default="https://reporting-api.app/browser-reports/YOUR-UUID"
When enabled, unresponsive crash reports will include a stack field with the JavaScript
call stack at the time the page became unresponsive. The format matches Error.prototype.stack and
respects Error.stackTraceLimit.
unresponsive crashes. OOM crashes destroy the JavaScript heap before
a stack can be captured — there's no call stack to report.
Testing Crash Reports
To verify your crash reporting configuration, you can trigger test crashes in Chrome using special URLs:
| Chrome URL | Effect |
|---|---|
| chrome://crash/ | Simulates a generic browser crash |
| chrome://memory-exhaust/ | Triggers an out-of-memory (oom) crash |
| chrome://hang/ | Makes the tab unresponsive (wait for browser to kill it) |
You can also test with the interactive Reporting API Crash Demo.
Preventing Crashes
While crash reports help you detect problems, prevention is better than detection:
Preventing OOM Crashes
- Profile memory regularly — Use Chrome DevTools Memory panel to identify leaks
- Limit cache sizes — Set maximum sizes for in-memory caches and implement LRU eviction
- Clean up references — Remove event listeners, clear intervals, null-out large objects
- Stream large data — Process data in chunks rather than loading everything at once
-
Monitor in production — Use
performance.memory(Chrome-only) to track heap usage
Preventing Unresponsive Crashes
- Use Web Workers — Move heavy computation off the main thread
-
Chunk long operations — Break work into smaller pieces with
requestIdleCallback - Avoid synchronous APIs — Never use sync XHR or other blocking operations
- Add safety limits — Use iteration limits and timeouts for loops and recursion
Server Configuration Examples
Nginx
server {
# ... your existing configuration ...
# Reporting endpoint for all report types including crashes
add_header Reporting-Endpoints 'default="https://reporting-api.app/browser-reports/YOUR-UUID"' always;
# Optional: Enable stack traces for unresponsive crashes
add_header Document-Policy 'include-js-call-stacks-in-crash-reports' always;
}
Ruby on Rails
# Add Reporting-Endpoints header for crash and other reports # Note: Use lowercase header names for Rack 3 compatibility config.action_dispatch.default_headers.merge!( "reporting-endpoints" => 'default="https://reporting-api.app/browser-reports/YOUR-UUID"', # Optional: Enable stack traces for unresponsive crashes "document-policy" => "include-js-call-stacks-in-crash-reports" )
Apache
Header always set Reporting-Endpoints 'default="https://reporting-api.app/browser-reports/YOUR-UUID"' # Optional: Enable stack traces for unresponsive crashes Header always set Document-Policy 'include-js-call-stacks-in-crash-reports'
Troubleshooting
Reports Not Appearing
- Check browser support — Crash reports only work in Chrome 96+, Edge 96+, and other Chromium browsers. Firefox and Safari do not support this feature.
-
Verify headers are sent — Use browser DevTools (Network tab) to confirm the
Reporting-Endpointsheader is present in responses. - Check allowed origins — Ensure your website's origin is whitelisted in your application settings.
- Wait for delivery — Crash reports are delivered asynchronously, often on the next page load. They won't appear immediately.
-
Trigger a test crash — Use
chrome://crash/orchrome://memory-exhaust/to generate a test report.
Missing Stack Traces
-
Check Document-Policy header — Stack traces require
Document-Policy: include-js-call-stacks-in-crash-reports. -
Only unresponsive crashes — Stack traces are only included for
unresponsivecrashes, not OOM. - Minified code — Use source maps in your error tracking tools to make stack traces readable.
Distinguishing Real Crashes from Test Data
-
Filter by URL — Test crashes from
chrome://URLs have different URL patterns. - Use staging environments — Test in staging before production deployment.
- Check user agent — Your test browser's user agent will be identifiable in reports.
Next Steps
- Cross-Origin Isolation — Configure COOP/COEP reporting
- Integrations — Route crash reports to your observability tools
- Getting Started — Set up your first application