Integrating Crashlytics for mobile app crash tracking
Firebase Crashlytics — de facto standard for collecting crash reports on iOS and Android. Main advantage over competitors: automatic stack trace symbolization without manual dSYM upload on iOS and mapping files on Android. When Xcode Cloud or Fastlane deliver build to Firebase App Distribution or TestFlight, Crashlytics automatically pulls symbols through Run Script in Build Phases.
iOS connection
Via Swift Package Manager add firebase-ios-sdk, then in AppDelegate:
import FirebaseCrashlytics
import FirebaseCore
@main
struct MyApp: App {
init() {
FirebaseApp.configure()
}
}
That's all needed for basic crash reporting — SDK intercepts uncaught exceptions and signals (SIGABRT, EXC_BAD_ACCESS) automatically.
Critical moment — dSYM upload. In Xcode ensure Build Settings → DEBUG_INFORMATION_FORMAT = DWARF with dSYM File for Release. Without this, dashboard shows memory addresses instead of function names. For CI add in Fastfile:
upload_symbols_to_crashlytics(
dsym_path: "./build/MyApp.app.dSYM.zip",
gsp_path: "./GoogleService-Info.plist"
)
Android connection
// build.gradle (app)
implementation("com.google.firebase:firebase-crashlytics:18.+")
implementation("com.google.firebase:firebase-crashlytics-ndk:18.+") // for C++ crashes
com.google.firebase.crashlytics plugin in build.gradle automatically uploads R8/ProGuard mapping file after each release build. Without plugin — load mapping manually via Firebase CLI.
Custom keys and logs for diagnostics
Bare stack trace often doesn't explain why it crashed. Crashlytics allows attaching context:
// iOS
Crashlytics.crashlytics().setCustomValue(userId, forKey: "user_id")
Crashlytics.crashlytics().setCustomValue("checkout", forKey: "last_screen")
Crashlytics.crashlytics().log("CartViewModel: starting payment")
// Android
Firebase.crashlytics.setCustomKey("user_id", userId)
Firebase.crashlytics.setCustomKey("last_screen", "checkout")
Firebase.crashlytics.log("CartViewModel: starting payment")
This data appears in Keys and Logs tabs of each crash report. In practice, this reduces diagnosis time: immediately see it crashed for anonymous user on payment screen, not just in URLSession.dataTask.
Non-fatal errors
Not all problems are crashes. Network error, failed JSON parse, timeout — all worth logging without ending session:
Crashlytics.crashlytics().record(error: NetworkError.timeout)
In dashboard, non-fatal errors go to separate Non-fatals section. Convenient for monitoring API degradation without crash-free rate growth.
Crash-free rate and alerts
Firebase Console shows crash-free users — percentage of sessions without crash. Production norm — above 99.5%. Set up email alert when falling below threshold through Firebase Alerts, or connect webhook to PagerDuty via Firebase Extensions.
What's included in the work
- Adding dependencies (CocoaPods / SPM / Gradle)
- dSYM upload configuration for iOS via Fastlane or Xcode script
- ProGuard/R8 mapping upload configuration for Android
- Adding custom keys for User ID, session, navigation path
- Logging non-fatal errors at key app points
- Alert setup in Firebase Console
Timeline
Basic integration with dSYM/mapping upload: 0.5–1 day. Adding custom keys and non-fatals in codebase — another 0.5–1 day depending on project size. Cost calculated individually.







