Skip to content
Everframe Docs
Documentation

Crash reporting

Not every bug has a user willing to file it. Uncaught errors become reports on their own.

Updated

Crash reporting is on by default — unlike replay and body capture, the payload is data the SDK already holds (the exception plus the breadcrumb trail), fully redacted. It is a client veto, so you can switch it off:

<EverframeProvider config={{ apiKey: 'evf_live_…', crashReporting: { disabled: true } }}>

What is caught

On the web, two mechanisms:

mechanismFires on
onerrorAn uncaught exception.
unhandledrejectionA promise rejection nobody handled.

Report a caught exception

Inside a component, use the hook:

import { useEverframe } from '@everframe/react';

const { captureException } = useEverframe();

async function save() {
  try {
    await saveCart();
  } catch (error) {
    captureException(error, {
      severity: 'warning',
      context: 'checkout.save-cart',
      metadata: { attempt: 2 },
    });
  }
}

Outside a component, import captureException from @everframe/react. It routes to the mounted provider and is a no-op before mount and after unmount.

The signature is captureException(error: unknown, options?: CaptureExceptionOptions): void. Options can add severity ('info', 'warning', or 'error'), a short context label, and JSON-shaped metadata for this occurrence. The SDK owns a bounded, redacted snapshot; invalid optional values are omitted without losing the core error. Details do not change handling, fatality, grouping, or retry identity.

Capture reports without opening UI and reuses redaction, user context, breadcrumbs, and the outbox. Returning does not confirm server receipt; delivery uses the existing retries. Both disabled and crashReporting.disabled suppress capture, as does kill().

Explicit errors use mechanism: 'captureException', handled: true, and fatal: false. Global errors use handled: false and fatal: false because an unhandled browser error does not imply process termination. Older SDK reports may omit fatal.

Set appVersion and appBuild in the provider config to identify the release and exact deployed build. appBuild appears in context.app.build for errors and user-filed reports. To translate minified production frames, pass that same exact build ID to the private source-map uploader.

What arrives

An unattended report is an ordinary envelope with top-level source set to error instead of manual — a web page survives an uncaught error, so the web SDKs never send crash — plus a payload.crash block:

{
  "exceptionType": "TypeError",
  "message": "cart.lines is undefined",
  "frames": [
    {
      "raw": "at Cart (cart.tsx:42:11)",
      "file": "cart.tsx",
      "function": "Cart",
      "line": 42,
      "col": 11
    }
  ],
  "mechanism": "onerror",
  "handled": false,
  "fatal": false,
  "occurredAt": "2026-06-15T11:59:58.400Z",
  "fingerprint": "9f2c1ab30d84e177"
}

The envelope keeps the Raw frames exactly as the SDK captured them. When a private map for the report’s exact app and build is ready, Everframe stores derived mapped locations and the error detail opens in Mapped mode. Raw remains available, including when processing is pending, partial, or failed.

mechanism is a plain string, not an enum, so v2 can add values without older receivers rejecting reports. Treat unknown values as opaque.

Grouping

fingerprint is 16 hex characters computed on the client from the exception type and the top frames. It is a heuristic, deliberately — it means grouping works with no server round-trip and no symbolication step. Two crashes sharing a fingerprint are the same bug often enough to be useful for triage; treat it as a strong hint, not an identity.

That client fingerprint remains in the report. By default it also drives active issues. An organization administrator can opt this React app into server grouping by mapped source position for future eligible errors. That workflow requires ready private maps plus separate default-closed processing and promotion controls; it does not regroup history. See Error triage & releases.

Duplicate reports and limits

The same error object is reported once per SDK instance across hook, top-level, and global capture. The first accepted capture determines classification. If you report a caught error and rethrow the same object, its report stays handled.

Explicit and automatic capture each accept one report per fingerprint and ten reports per SDK instance. Their allowances are independent. Distinct error objects with the same fingerprint can still be throttled, so counts describe received reports rather than every failure. Transport retries preserve the report ID and do not add server occurrences.

What comes with it

An error report has a title generated from the exception and an empty description. It includes what the SDK already had in memory: the breadcrumb trail leading to the throw, with the console and network entries on it, plus the route, device and app. There is no screenshot and no replay — nothing was frozen, because nobody opened the reporter. That is still the difference between a stack trace and a timeline.

React error boundaries

An error caught by a boundary is handled. Forward it explicitly from the boundary’s componentDidCatch method:

import { captureException } from '@everframe/react';

// In your error boundary class:
componentDidCatch(error: Error) {
  captureException(error);
}