Moving from Sentry
You should not move crash reporting to a service you have not watched work. So do not move it yet. Point your app here, keep your Sentry DSN as the upstream, and let both backends receive the same crashes from the same builds for as long as you like.
Why this works at all
Because there is no SDK of ours in the way.
Monitor takes Sentry format envelopes from the MIT licensed Sentry SDKs, unchanged. Adopting it is a change to one DSN string: no rewrite, no shim, no second package fighting the first one for the error handler. That is also what makes the comparison below possible, because the envelope Monitor receives is byte for byte the one Sentry would have received, so it can forward it on without translating anything.
The week, in five steps
Create a project here and copy its DSN
One DSN for the project. Take it from the key card on the project's Monitor settings screen.
Change one string in your app
The DSN, and nothing else. Same SDK, same version, same configuration. If you have not set an environment yet, set one now: neither SDK does it for you, and comparing two backends is easier when both can tell a tester's crash from a customer's.
options.dsn = 'https://<public key>@monitor.unrealops.ai/ingest/<project>';dsn: "https://<public key>@monitor.unrealops.ai/ingest/<project>",Paste your old Sentry DSN into the upstream field
On the same settings screen, under Mirror to another Sentry. Save it, and every envelope this ingest accepts is forwarded there unchanged.
https://abc123@o0.ingest.sentry.io/1234567It takes effect on the next event. There is no deploy in this step, because the app is already sending to one address and the second one is decided here.
Compare on your own crashes
Both backends now see the same traffic from the same builds, so the comparison is your real production crashes rather than a demo. The settings screen states the last outcome rather than implying it with silence: it says when something was last forwarded and to which host, or that the last attempt failed and why.
While you are comparing, you can keep uploading debug symbols or source maps to both. They are two independent steps in one build, and neither knows about the other.
Stop, whichever way you decide
Satisfied, clear the upstream field and the forwarding stops on the next event. Unconvinced, put your Sentry DSN back in the app and nothing here ever sees another event. Either way it is one string, and neither direction needs a redeploy to stop the thing you are stopping.
What is forwarded, exactly
The bytes you sent, not our interpretation of them.
The raw envelope is what carries attachments, sessions and everything Monitor has no product for, and somebody comparing two backends for a week is entitled to have compared the same traffic. So the forward sends the envelope it was given. The url and the authentication header differ, because they name the upstream rather than us, and one field of the envelope header does: the DSN inside it is stripped, which the Sentry specification requires and without which every forward would be refused. Every item header and payload is untouched.
What it cannot cost you
Three properties, and they are the three ways a feature like this normally goes wrong.
- It never changes what your app is told. The forward is scheduled after your events are stored and after this ingest has already answered, and nothing it returns is read. An upstream that is down, slow or lying is indistinguishable from a healthy one as far as the app sending crashes is concerned.
- It is bounded and never retried. A forward gets two seconds and one attempt. Your events are already safe here, and a retry queue would turn somebody else's outage into stored bytes and invocations on an account whose whole promise is that it cannot surprise you with a charge.
- Stopping is not a negotiation. Clearing the field takes effect on the next event rather than the next deploy. A migration aid you cannot switch off is a hostage situation.
What does not come with you
Mirroring copies new events forward. It is not an import, and several things here are genuinely less than what you have.
- History. Nothing that already happened is copied. The comparison starts from the moment you save the upstream, and your existing issues stay where they are.
- Issue state. Assignments, comments, resolutions, ignore rules and alert rules are not transferred and there is no equivalent for some of them.
- Profiles and replays. Transactions and log lines are stored here, out of the same event allowance your errors come from. Profiles and replays are not: they are acknowledged at ingest so your SDK does not retry them, then counted where you can see them. That is the one case where keeping the upstream permanently is the right answer rather than a trial, because a copy of every envelope goes to Sentry and replay carries on being recorded there.
- Paging. Alerts reach email, Slack and any https endpoint you register. There is no rota, no escalation policy and nothing that phones a person.
- Uploaded artifacts. Debug symbols and source maps already in Sentry are not readable by us. Upload from the build to both while you compare.
Differences worth knowing before you compare
So that a difference you notice reads as a decision rather than a bug.
Grouping ignores minified function names. A minifier renames handleCheckout to t on one build and n on the next, so including the name would make every deployment a fresh copy of every open issue. The cost, stated plainly: two different bugs in the same chunk with the same exception type and the same stack shape can group together.
Quotas are pooled and they refuse. The monthly event allowance belongs to the organization and is spent across every project it owns. At the ceiling, ingest answers 429 with Retry-After, your SDK backs off, and the refusals are counted by reason on the usage screen. There is no overage rate on any plan, which cuts both ways: you cannot be surprised by an invoice, and you can be surprised by missing data. Raising the cap undoes it immediately.
Retention is shorter on the small plans. Seven days on the free tier, thirty on Solo, ninety on Studio. Events past that are deleted and an issue's counts are recomputed from what survives, so the list never quotes a number for events it cannot open.
Symbol storage is a pool too, and it evicts. When it fills, the oldest release's symbols are deleted so the newest release's fit. The build in production always resolves; a build from two months ago may stop. Readable stack traces has the whole rule.