# Migrate from Sentry to Belvador

> Replace an existing Sentry SDK with the matching Belvador package without reporting errors twice.

Belvador speaks the same protocol as Sentry, so moving an app over is mostly swapping a package and a DSN. The one rule that matters: **only one SDK may report errors** — run both and every error arrives twice.

## Pick the replacement

| You have | Replace with | Guide |
|---|---|---|
| `@sentry/browser` | `@belvador/browser` | [Browser](https://belvador.dev/en/docs/sdk/browser) |
| `@sentry/react` | `@belvador/react` | [React](https://belvador.dev/en/docs/sdk/react) |
| `@sentry/tanstackstart-react`, or Sentry wired by hand in TanStack Start | `@belvador/tanstack-start` | [TanStack Start](https://belvador.dev/en/docs/sdk/tanstack-start) |
| `@sentry/cloudflare` | `@belvador/cloudflare` | [Cloudflare Workers](https://belvador.dev/en/docs/sdk/cloudflare) |
| `@sentry/node` | keep it, change the DSN and add the scrubbing hook | [Node.js](https://belvador.dev/en/docs/sdk/node) |
| `sentry-sdk` (Python) | keep it, change the DSN and add the scrubbing hook | [Python](https://belvador.dev/en/docs/sdk/python) |
| Another Sentry SDK | keep it and change the DSN — not verified by Belvador | — |

## Steps for JavaScript apps

1. **Create a project** in Belvador and copy its DSN.
2. **Install** the Belvador package, pinned to 0.6.1.
3. **Replace imports.** The common functions have the same names:

```ts
// Before
import * as Sentry from "@sentry/react";
Sentry.captureException(error);

// After
import { captureException } from "@belvador/react";
captureException(error);
```

4. **Replace `Sentry.init`** with Belvador's `init` (or `withBelvador` on Workers), using the setup from the guide. Remove the old `Sentry.init` call — Belvador's `init` does not take over a client that is already running.
5. **Remove** every `@sentry/*` SDK package from `package.json` (keep `@sentry/cli` if CI uses it for source maps). Belvador's packages bring their own pinned engine; installing `@sentry/*` next to them is not needed.
6. **Update CSP**: replace Sentry's ingest host with `https://ingest.belvador.dev` in `connect-src`.
7. **Point CI at Belvador** for source maps: keep `sentry-cli`, change `SENTRY_URL` and the token — see [Source maps](https://belvador.dev/en/docs/source-maps).
8. **Deploy and verify**: run the [connection check](https://belvador.dev/en/docs/sdk/verify) for each runtime and confirm the **Connection** tab says **Verified**. A tagged error works with any Sentry SDK, so you can check before switching packages. Then confirm a real error appears once.

## Options that change

| Sentry option | In Belvador |
|---|---|
| `dsn`, `release`, `environment`, `dist`, `sampleRate`, `ignoreErrors`, `beforeSend`, `beforeBreadcrumb`, `maxBreadcrumbs`, `debug` | Same meaning |
| `allowUrls`, `denyUrls` (browser) | Same meaning |
| `enabled` | Use `disabled: true` |
| `integrations`, `defaultIntegrations` | Not accepted; Belvador sets up what it needs. Breadcrumbs are turned on with `instrument` |
| `tracesSampleRate`, `tracePropagationTargets`, `replaysSessionSampleRate`, `profilesSampleRate`, `enableLogs` | Not available — the SDKs send errors only. Send traces and logs with [OpenTelemetry](https://belvador.dev/en/docs/otel/overview); link errors across tiers with [`tracePropagation`](https://belvador.dev/en/docs/sdk/tracing) |
| `sendDefaultPii` | Always off |
| `tunnel`, `transport` | Not available — events go only to your DSN |
| `maxValueLength` | Fixed at 8,192 characters |

TypeScript points out options that no longer exist.

## Behaviour that changes

- `setUser` keeps only `id`. Emails, usernames and IP addresses are removed before sending.
- Automatic breadcrumbs (console, clicks, fetch, XHR, navigation) are off until you turn them on.
- Attachments are dropped unless `attachments: true`.
- `Sentry.showReportDialog` and the boundary's `showDialog` are not available.
- Request bodies, cookies and auth headers are removed by the SDK and again by your node.

## Keeping an existing Sentry SDK

Any Sentry SDK can send to a Belvador DSN, so you can also just change the DSN. You then keep that SDK's own defaults: it may send tracing data (dropped by your node and counted as **Not supported yet**), personal data if `sendDefaultPii` is on, and automatic breadcrumbs. Your node still scrubs before storing. For JavaScript apps the Belvador packages are the safer choice.

## Existing issues

Belvador starts with an empty history: issues and events already in Sentry are not imported. Keep Sentry read-only for a while if you need to look things up.
