Firebase Crashlytics Setup
Why Crash Reporting Matters
In production, users encounter crashes you cannot reproduce locally. Without crash reporting, you rely on Play Store reviews — which are delayed, vague, and lack stack traces. Crashlytics gives you real-time crash data with full stack traces, device info, and user impact.
Adding Crashlytics to Your Project
Add the Crashlytics dependencies to your module-level build.gradle.kts:
plugins {
id("com.android.application")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")
}
Enable automatic crash reporting in the firebase-crashlytics plugin block:
// At the top of build.gradle.kts
firebaseCrashlytics {
mappingFileUploadEnabled = true
}
Non-Fatal Exception Logging
Not all issues are hard crashes. You can log caught exceptions to track handled errors:
try {
processData(rawInput)
} catch (e: ParseException) {
Firebase.crashlytics().log("Parse error on input: ${rawInput.take(50)}")
Firebase.crashlytics().recordException(e)
}
Non-fatal exceptions appear in the Crashlytics dashboard alongside fatal crashes, giving you visibility into the full error landscape.
Adding Custom Keys and Logs
Attach context to crash reports to aid debugging:
// Add user-specific context
Firebase.crashlytics().setUserId("user_12345")
Firebase.crashlytics().setCustomKey("feature_flag_new_ui", true)
Firebase.crashlytics().setCustomKey("account_tier", "premium")
// Add breadcrumbs leading to the crash
Firebase.crashlytics().log("Navigated to settings screen")
Firebase.crashlytics().log("Changed theme preference")
Symbolication and Mapping Files
Why Symbolication is Necessary
When you build a release APK or AAB with ProGuard/R8 enabled, class names, method names, and line numbers are obfuscated. A crash stack trace in production looks like:
java.lang.NullPointerException:
at com.a.b.c.a(SourceFile:12)
at com.a.b.d.b(SourceFile:45)
``
This is unreadable. **Mapping files** reverse the obfuscation, converting minified names back to their original form.
### How Mapping Files Work
When R8 minifies your code, it generates a `mapping.txt` file in `app/build/outputs/mapping/release/`. This file contains:
com.example.ui.SettingsFragment -> com.a.b.c:
void onSaveClicked() -> a
void loadPreferences() -> b
com.example.data.User currentUser -> c
Crashlytics uploads this mapping file and automatically deobfuscates stack traces.
### Ensuring Mapping File Upload
For Gradle builds, the Crashlytics plugin handles upload automatically when `mappingFileUploadEnabled = true`. For CI/CD pipelines, ensure the mapping file is not cleaned before upload:
```kotlin
// In your build script
firebaseCrashlytics {
mappingFileUploadEnabled = true
}
// The mapping file is at:
// app/build/outputs/mapping/release/mapping.txt
In CI environments, make sure you do not run ./gradlew clean between the build and the Crashlytics upload step.
Verifying Upload
After a release build, check the Firebase console under Crashlytics > Settings > Mapping files to confirm the mapping file was uploaded for your app version.
Crash Alerts and Monitoring
Crashlytics Dashboard
The Crashlytics dashboard provides:
- Crash-free users — Percentage of sessions without crashes
- Issue grouping — Crashes grouped by stack trace similarity
- Trends — Whether crash rates are improving or worsening
- Device/OS breakdown — Which devices and Android versions are affected
- Breadcrumbs — User actions leading up to the crash
Configuring Alerts
Set up alerts in Firebase Console:
- Go to Crashlytics > Alerts
- Create alerts for:
- Crash rate exceeds threshold — Alert when crash-free users drop below a percentage
- New issue detected — Get notified when a new crash appears
- Regression spike — Alert on sudden increases in a known issue
Using the Crashlytics API
For automated monitoring, use the Firebase Admin SDK or REST API:
// Check crash rate programmatically (admin context)
// Firebase REST API or BigQuery export
// BigQuery export query example:
// SELECT
n// issue_id,
// issue_title,
// count(*) as crash_count
// FROM `project.crashlytics.crashlytics`
// WHERE timestamp > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY)
// GROUP BY issue_id, issue_title
// ORDER BY crash_count DESC
Crash Rate Benchmarks
- < 1% crash-free — Critical; halt rollout and fix immediately
- 1-2% — Investigate priority issues, consider rollback
- 2-5% — Monitor trends, schedule fixes for next release
- > 5% — Unacceptable for production; immediate action required
BigQuery Integration
Export Crashlytics data to BigQuery for custom analysis:
- Enable BigQuery export in Firebase Console
- Query crash data with SQL
- Build custom dashboards or integrate with existing monitoring tools
- Set up alerts via Cloud Functions triggered by BigQuery queries
Quiz
1. Why do crash stack traces appear obfuscated in production builds?
2. What is the purpose of recording non-fatal exceptions in Crashlytics?
3. What is a reasonable crash-free user percentage target for a production app?
4. What should you ensure in CI/CD to allow Crashlytics to deobfuscate stack traces?
Flashcards
Question
What does Firebase.crashlytics().recordException() do?
Click to reveal answer
Answer
Logs a non-fatal exception to Crashlytics for monitoring handled errors that do not crash the app.
Question
Where is the ProGuard mapping file located after a release build?
Click to reveal answer
Answer
app/build/outputs/mapping/release/mapping.txt
Question
What does the crash-free users metric represent?
Click to reveal answer
Answer
The percentage of user sessions that did not experience a fatal crash, indicating overall app stability.
Question
What is the purpose of Crashlytics breadcrumbs?
Click to reveal answer
Answer
They record user actions leading up to a crash, providing context for what the user was doing when the crash occurred.
Revision Notes
Key Takeaways
- 1. Crashlytics provides real-time crash data with full stack traces, device info, and user impact
- 2. ProGuard/R8 obfuscation requires mapping files for readable stack traces — ensure they upload correctly
- 3. Track non-fatal exceptions alongside fatal crashes for complete error visibility
- 4. Target 99.5%+ crash-free users in production; anything below 1% requires immediate attention
- 5. Use custom keys and breadcrumbs to attach debugging context to crash reports
Interview Tips
- • Explain how you would set up crash monitoring for a newly launched app
- • Discuss strategies for reducing crash rates before a major release
- • Know how mapping files work and why they are essential for production debugging
- • Be able to describe your alerting thresholds and escalation process for critical crashes
Cheat Sheet
Crash Reporting Cheat Sheet
Setup:
- Add
firebase-crashlytics-ktxdependency - Enable
mappingFileUploadEnabled = true - Use Firebase BOM for version management
Key APIs:
Firebase.crashlytics().recordException(exception)
Firebase.crashlytics().log("message")
Firebase.crashlytics().setUserId("id")
Firebase.crashlytics().setCustomKey("key", value)
Mapping Files:
- Located at
app/build/outputs/mapping/release/mapping.txt - Auto-uploaded by Crashlytics Gradle plugin
- Do not clean before upload in CI/CD
Crash Rate Benchmarks:
- < 1%: Critical
- 1-2%: Investigate
- 2-5%: Monitor
99.5%: Production target