Production Stability Monitoring for Mobile Apps
A 99.2% crash-free rate sounds good until you calculate: at 100,000 DAU, that's 800 crashes per day. Without monitoring tools, the team learns about problems from App Store reviews—that is, several hours after hundreds of users have already encountered the error.
What We Monitor
Crashes and Errors
Primary tool—Firebase Crashlytics. Automatically intercepts fatal and non-fatal exceptions, groups by stack trace, shows affected users and sessions. Key metrics for daily control:
- Crash-free users (not sessions)—real picture by users
- Velocity alerts—Crashlytics can send a notification when a new crash affects N% of sessions per hour
- Regression tracking—crash was closed, appeared again in new version
For NDK/C++ components, separately configure nativeSymbolUploadEnabled = true and upload .so symbols via Crashlytics CLI.
ANR and Hangs (Android)
Google Play Console → Android Vitals → ANR rate. Google's threshold—0.47% ANR rate; above that, the app is marked as problematic and drops in search rankings. ANR on the main thread usually means blocking I/O or synchronous database query in onCreate.
StrictMode in debug builds helps catch such issues before production:
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectNetwork()
.penaltyLog()
.build()
)
}
Performance (iOS MetricKit)
MetricKit from iOS 14 delivers aggregated diagnostics data: hang rate, crash rate, disk writes, launch time. Data arrives once per day in didReceive(_ payloads: [MXMetricPayload]). For monitoring launch time, applicationLaunchMetrics.histogrammedTimeToFirstDraw is critical—a 200ms degradation already impacts retention.
Custom Events
Firebase Crashlytics allows manual logging of non-fatal errors—important for business-critical flows:
// iOS: log payment error as non-fatal
Crashlytics.crashlytics().record(error: paymentError)
Crashlytics.crashlytics().log("Payment failed at step: \(step)")
// Android
FirebaseCrashlytics.getInstance().recordException(exception)
FirebaseCrashlytics.getInstance().log("Checkout step: $step")
This creates "soft" errors in Crashlytics—user didn't see a crash, but the transaction failed.
Alerting
Set up notifications in Slack or Telegram via Crashlytics webhooks or Firebase Extensions. Minimum set of alerts:
| Event | Threshold | Channel |
|---|---|---|
| New crash in release build | Any | #crashes-mobile |
| Crash-free rate dropped | < 99.5% per hour | #incidents |
| ANR rate (Android) | > 0.3% | #android-ops |
| Velocity alert | > 0.1% sessions in 30 min | #incidents (pager) |
Workflow
Initial setup: Crashlytics integration, velocity alerts configuration, Slack connection.
Daily monitoring: review new crashes, cross-check with Android Vitals and App Store Connect.
Regular reports: weekly crash-free rate breakdown by OS version and devices.
Timeline Estimates
Full monitoring setup—1–3 days depending on project complexity. Ongoing monitoring—discussed individually.







