Get started
Catching render errors (React)
When a component throws, there is no screen left to point at — but there is a
message, a stack and a component stack, which is the best evidence a bug report
ever carries. BugReportBoundary catches it and hands your fallback the error
and a report() function:
import { BugReportBoundary } from "bugbottle/react";
<BugReportBoundary
endpoint="/api/feedback"
fallback={(error, report, sending) => (
<div role="alert">
<p>This part of the page stopped working.</p>
<button onClick={report} disabled={sending}>
{sending ? "Sending…" : "Tell us what happened"}
</button>
</div>
)}
>
<Orders />
</BugReportBoundary>;report() sends a bug report whose message is the error, its stack and the
component stack, and resolves true when the endpoint accepted it — so the
button can say "sent". Nothing is sent until it is called: a report is a
message from a person, and sending one on their behalf without asking is
telemetry, which this library is not. onReport(error, id) and
onError(error) are there for the surrounding application.
Calling it twice files one report: a second call while the first is in flight
gets the same promise, and a call after a successful send does nothing, because
it is the same render error either way. A send that failed can be tried again.
The third argument, sending, is true while one is in flight, for a button
that should say so.
For the errors that reach the root, React 19 takes two handlers, and
createRootErrorHandlers builds both:
import { createRoot } from "react-dom/client";
import { createRootErrorHandlers } from "bugbottle/react";
createRoot(node, createRootErrorHandlers({ endpoint: "/api/feedback" })).render(<App />);These do send by themselves, because there is nobody left to ask. Each distinct
error is sent once per dedupeMs (60 000 by default, by the same fingerprint
the client and the server share), so a component that throws on every render
sends one report rather than a thousand. Say so in your privacy notice, and
pass scrub: scrubReport if a message could carry anything personal.