crashrelay-browser
Tiny, dependency-free browser snippet that catches window.onerror /
unhandledrejection and reports them to a
crashrelay ingestion endpoint,
which files a Jira/GitHub Issues ticket.
Zero runtime dependencies. Plain ESM build — loadable via
<script type="module"> or a bundler import.
Install
npm install crashrelay-browser
Usage
import { initErrorReporter } from 'crashrelay-browser';
initErrorReporter({
endpoint: 'https://your-api.example.com/report',
token: 'the-ingestion-token-from-crashrelay-init',
});
Or directly in a page with no build step:
<script type="module">
import { initErrorReporter } from 'https://esm.sh/crashrelay-browser';
initErrorReporter({ endpoint: 'https://your-api.example.com/report', token: '...' });
</script>
Call dispose() on the returned handle to remove the listeners:
const reporter = initErrorReporter({ endpoint, token });
reporter.dispose();
How it reports
fetch(..., { keepalive: true }) is the primary transport — it's the only
one of the two browser mechanisms that can carry a custom Authorization
header. navigator.sendBeacon is used only as a fallback if fetch throws,
with the token moved into the request body instead (since sendBeacon
can't set headers at all) — a deliberate trade-off against sendBeacon's
stronger "survives page unload" guarantee.
The token is not a secret
The token you pass is a public "write key," the same trust model as a
Sentry DSN — it's visible in the browser's network tab to anyone who opens
devtools. Its abuse-mitigation is rate-limiting and deduplication on the
crashrelay ingestion endpoint, not confidentiality. Never put a real API
credential (Jira token, GitHub PAT) here.
Limitations
- Only catches errors that reach
window.onerror/unhandledrejection— errors swallowed by a try/catch elsewhere in your app never surface here. - No batching — each error is its own request. For a very error-heavy page,
pair with
crashrelay's server-side dedup rather than expecting client-side throttling.