Crash Reporting and Monitoring: Turning Noise into Fixable Signal

We took over an app with a Crashlytics dashboard showing over 400 open, unresolved crash groups, and unsurprisingly nobody on the client's team was actually looking at it anymore — the volume had made the dashboard functionally useless as a signal. The tooling wasn't the problem; the team had no triage process turning crash reports into prioritized, actionable work.
Our first pass was almost entirely deletion and consolidation, not fixing. A large fraction of the 400 groups were duplicate symbolication failures from a missing dSYM upload step in CI, meaning the same crash was showing up under a dozen different unsymbolicated stack traces instead of one grouped issue. Fixing the CI pipeline to reliably upload dSYMs on every release collapsed those into a handful of real, addressable crash groups.
We then set an explicit triage rule: any crash group affecting more than 0.1% of sessions in a rolling 7-day window gets a ticket within 24 hours, anything below that threshold gets reviewed weekly rather than immediately. Without a numeric threshold, engineers were spending time on rare, low-impact crashes that happened to be recently reported while a crash affecting 3% of sessions sat unaddressed because it had been open longer and felt less urgent to revisit.
Non-fatal error tracking turned out to be as valuable as crash tracking once we set it up properly — logging handled exceptions (a failed API parse, a retried network call, an unexpected nil) as non-fatal events rather than silently swallowing them surfaced problems that were degrading the experience without technically crashing the app, including one silent failure in a payment retry path that had been quietly failing for an estimated 2% of transactions before anyone noticed.
We also added release-health gating to the CI/CD pipeline itself — a new release's crash-free session rate is compared against the previous release's rate at the 24-hour and 72-hour marks after a staged rollout begins, and a rollout is automatically paused if crash-free rate drops more than a defined threshold, rather than relying on someone remembering to check the dashboard after each release.
Within two months of instituting the triage threshold and closing the dSYM gap, the open crash group count dropped from 400-plus to under 20, and crash-free session rate improved from 97.2% to 99.6%. The tooling didn't change — the process turning crash noise into a queue of specific, prioritized fixes did.

