Skip to content

Framework guide

Error tracking for React apps

@belvador/react reports render errors with the component stack, React 19 root errors and anything uncaught in the browser. It wraps Sentry's JavaScript engine 10.76.2, scrubs before sending, and the events are stored on your own node.

Start freeReact

Updated Oct 25, 2026

The short answer#

  • Install @belvador/react, call init with your DSN and wrap the app in ErrorBoundary.

  • It reports render errors with the component stack, React 19 root errors and uncaught browser errors.

  • Events are scrubbed in the browser and again on your node in your Hetzner project.

  • Coming from @sentry/react, you change the import and the DSN.

What it captures#

  • Render errors through ErrorBoundary, with the component stack, while your fallback replaces the blank page.

  • React 19 root errors — onUncaughtError, onCaughtError and onRecoverableError via reactErrorHandler(). React 19 handles many errors itself, so without these hooks they never reach window.onerror.

  • Uncaught exceptions and unhandled promise rejections once init has run.

  • Stack traces mapped to your source when you upload source maps from CI (source maps).

What is not sent by default: breadcrumbs, attachments and trace headers are opt-in, and there is no replay or browser tracing (capabilities).

Install#

Terminal
npm install @belvador/react@0.6.1

Initialize (React 18 and 19)#

src/instrument.ts
import { init } from "@belvador/react";init({  dsn: "https://<public-key>@ingest.belvador.dev/<project-id>",  release: import.meta.env.VITE_APP_VERSION, // your build or commit id  environment: import.meta.env.MODE,});

Import that file on the first line of src/main.tsx, before App, so a module that fails while loading is still reported:

src/main.tsx
import "./instrument"; // first line: starts Belvador before App's modules loadimport { createRoot } from "react-dom/client";import { ErrorBoundary } from "@belvador/react";import App from "./App";const root = document.getElementById("root");if (!root) throw new Error("Root element missing");createRoot(root).render(  <ErrorBoundary fallback={<p>Something went wrong.</p>}>    <App />  </ErrorBoundary>,);

On React 19, also pass reactErrorHandler() to the root options; the React guide shows both versions and the Content Security Policy line to add.

Check it works#

Call verifyIntegration() once from production, or throw a tagged test error, and the project's Connection tab shows Verified for the browser (verify a connection).

Limits#

  • Browser only. For server rendering on Workers use TanStack Start; for a Node.js server use Node.js.

  • Next.js is not covered by a tested Belvador package yet.

  • No session replay and no user feedback dialog: the dialog loads a script from the DSN host, which Belvador never does.

Questions#

I already use @sentry/react. What changes?#

Replace the import with @belvador/react and the DSN with your Belvador DSN. captureException, withScope, setTag and ErrorBoundary keep their names (migrate from Sentry).

How big is it?#

In the 0.4.0 release build, @belvador/react with init and ErrorBoundary measured 37.6 KB gzip; @sentry/browser with its default init measured 28.7 KB in the same build. The SDK reference lists the current packages.

Try it on your own Hetzner project

Free during the beta. Hetzner bills the server; Belvador never bills per event.