Use BugCapsule
Migrate from Sentry
Move crash and error reporting to BugCapsule in two steps. First change one line, the DSN, and your Sentry SDKs report to BugCapsule as they are. Then, at your pace, switch to the BugCapsule SDK: the same crash reporting, plus a replayable Capsule for each crash and fixes verified by replay.
What you get
| Area | In BugCapsule |
|---|---|
| Errors and crashes | Issues grouped by fingerprint, with symbolicated stack traces, every thread, breadcrumbs, user, tags and contexts. Native crashes, ANRs and app hangs on Android, iOS and Flutter, reported on the next launch with the release and breadcrumbs of the run that crashed. |
| Release health | Crash-free sessions and users per release; crashed and abnormal sessions. |
| Performance | Transactions, spans, distributed traces and web and mobile vitals. |
| Alerts and integrations | New issue, regression, escalating, frequency, crash-free rate and duration alerts by email, Slack and signed webhooks; GitHub and Jira issues. |
| User feedback | Feedback linked to the event it is about. |
| Replay (BugCapsule SDK) | A Capsule for the failure: the actions, network, state and timing that led there, which the CLI replays against your code. Native crashes get one too, built on the next launch. |
| Verified fixes (BugCapsule SDK) | An issue is verified fixed only when every Capsule of it was replayed against a fixed build without failing, and a release gate in CI stops a release that brings a fixed bug back. |
Step 1: change the DSN
BugCapsule accepts what Sentry SDKs send. Find your project's DSN in the dashboard under Project settings › Keys › Sentry SDKs. It looks like https://<ingest key>@<your BugCapsule API host>/<number>: put the project's ingest key (bci_…) in place of <ingest key>. Replacing the ingest key shows the complete DSN once.
No Sentry SDKs section in your project settings? Your BugCapsule backend doesn't accept Sentry SDK traffic yet; skip to step 4.
Sentry.init({
dsn: 'https://bci_…@api.bugcapsule.com/42', // was your Sentry DSN
release: 'shop-web@1.4.0+52',
tracesSampleRate: 0.2,
});
<meta-data android:name="io.sentry.dsn" android:value="https://bci_…@api.bugcapsule.com/42" />
SentrySDK.start { options in
options.dsn = "https://bci_…@api.bugcapsule.com/42"
}
await SentryFlutter.init(
(options) => options.dsn = 'https://bci_…@api.bugcapsule.com/42',
appRunner: () => runApp(const MyApp()),
);
Ship a build and trigger a test error. It shows up under Issues within seconds. The ingest key can only send data, so it can sit in the app like your Sentry DSN did.
What carries over, and what doesn't
| Sentry SDK sends | In BugCapsule |
|---|---|
| Error and crash events (exceptions, threads, breadcrumbs, user, tags, contexts, debug images) | Issues and events, grouped, symbolicated and alerted on like any other event. |
| Sessions from mobile and browser SDKs | Release health (crash-free sessions and users). |
| Transactions and spans | Performance and traces. |
| User feedback | Feedback, linked to its event. |
| Aggregated sessions from server SDKs; attachments and minidumps; profiles; session replays; cron check-ins; metrics | Not kept. The request still succeeds, so your app behaves the same. |
| History already in Sentry | Not imported. Keep Sentry read-only until you no longer need it. |
Step 2: upload symbols with BugCapsule's tools
sentry-cli uploads go to Sentry, not to BugCapsule. Upload the same files with the tool for your platform, for every release; see Release symbols & maps:
| Instead of | Use |
|---|---|
sentry-cli sourcemaps inject / upload | bugcapsule-cli sourcemaps inject / upload from @bugcapsule/cli, with --release |
| Sentry Android Gradle plugin (ProGuard, native symbols) | The BugCapsule Gradle plugin: mapping.txt and unstripped .so files |
sentry-cli debug-files upload (dSYMs) | bugcapsule-upload-dsyms.sh in an Xcode build phase or CI |
sentry-cli debug-files upload (Flutter --split-debug-info) | bugcapsule symbols upload |
dSYMs and native libraries are matched by the image's UUID or build id, which is the same whichever SDK reported the crash, so these uploads also resolve crashes sent by Sentry SDKs. Source maps uploaded with --release are found by release and file name. ProGuard mappings and Dart obfuscation maps are found through ids the BugCapsule Gradle plugin and bugcapsule symbols new-id put into the build, which Sentry SDKs don't send: deobfuscated Android and obfuscated Flutter frames need the BugCapsule SDK (step 4).
Step 3: recreate alerts and integrations
Alert rules don't move automatically. Recreate the ones you rely on under Alerts:
| Sentry alert | BugCapsule trigger |
|---|---|
| A new issue is created | New issue |
| The issue changes state from resolved to unresolved | Regression |
| The issue is escalating | Escalating issue |
| Number of events / users in an issue | Event frequency / Users affected |
| Crash free session / user rate | Crash-free rate |
| Transaction duration | Transaction duration |
Actions: email, Slack (incoming webhook), signed webhooks, and creating GitHub or Jira issues, configured under Monitoring settings › Integrations. Ownership rules use the same path: / module: / url: / tags. matchers. BugCapsule adds Capsule ready, Verification failed and Issue verified fixed.
Step 4: switch to the BugCapsule SDK
The BugCapsule SDK reports the same errors, crashes, sessions and traces, and records the Capsule that replays each failure. Install it for your platform (Flutter, Android, iOS, Web), then move your calls:
| Sentry | BugCapsule |
|---|---|
Sentry.init({ dsn, release, environment, tracesSampleRate, beforeSend }) | BugCapsule.init / start with an SDK token; release, environment, tracesSampleRate, beforeSend in the monitoring options (Monitoring) |
captureException, captureMessage | BugCapsule.captureException, BugCapsule.captureMessage |
setUser, setTag, setExtra, setContext | The same names on BugCapsule |
addBreadcrumb | BugCapsule.addBreadcrumb |
configureScope, withScope | BugCapsule.configureScope, BugCapsule.withScope |
startSpan, startTransaction | BugCapsule.startSpan (Flutter, iOS, web), BugCapsule.startTransaction |
captureFeedback and the feedback widget | BugCapsule.captureFeedback and the platform's feedback form |
flush, lastEventId | BugCapsule.flush, BugCapsule.lastEventId |
Sentry's NDK / Cocoa crash handlers; sentry_flutter's native layer | bugcapsule-ndk on Android; built in on iOS; bug_capsule_native for Flutter (native crashes of the app, the engine and plugins) |
Then remove the Sentry SDK. While both are in the app, send errors from one of them only: either keep Sentry's DSN pointed at BugCapsule and set monitoring off in the BugCapsule SDK, or remove Sentry's error handlers. Two reporters with monitoring on send every error twice.
On the web you can do this gradually. With the DSN pointed at BugCapsule, add sentryCompanion() to Sentry.init and the BugCapsule SDK with monitoring: false: Sentry's events arrive in BugCapsule already linked to the Capsule recorded for the same error. See Keep Sentry alongside.
Step 5: verify fixes and gate releases
- When an issue has Capsules, replay one with
bugcapsule run <id>, fix it, and runbugcapsule verify <id>against your build. The issue shows Verified fixed in <release> once every Capsule of it passes. - Add
bugcapsule gate --release <release> --platform <platform>to your release pipeline: it replays the Capsules of resolved issues against the build and fails the job when one comes back. See Release gate.
Checklist
- Sentry SDK DSNs point at BugCapsule in every app and environment you keep running.
- Symbols, mappings and source maps upload with BugCapsule's tools for every release.
- Alert rules and integrations you rely on exist in BugCapsule.
- The BugCapsule SDK is installed, with exactly one error reporter on.
- A native crash, a JavaScript error and an ANR or app hang from a QA build each show up as issues with readable frames.
- Someone owns removing the Sentry SDK and closing the Sentry project.