Quick answer: A crash is an unhandled exception or signal (like SIGSEGV or SIGABRT) that terminates the process immediately.
This guide covers crash reporting for mobile games iOS Android in detail. Mobile games crash. On Android, you are dealing with thousands of device configurations, GPU driver bugs, and memory limits that vary by a factor of four between low-end and flagship phones. On iOS, the hardware is more consistent but the OS is aggressive about killing apps that use too much memory. Without automated crash reporting, you are relying on one-star reviews and vague player emails to find out about stability problems. A proper crash reporting pipeline catches every crash, groups them by root cause, and gives you the stack trace and device context to fix them.
Choosing a Crash Reporting Service
Firebase Crashlytics is the most widely used crash reporting tool for mobile games and it is free. It integrates with both Unity and native Android/iOS builds, provides real-time crash alerts, and groups crashes by stack trace similarity. For most indie mobile games, Crashlytics is the right starting point.
If you are building with Unity, the Unity Cloud Diagnostics service provides crash reporting integrated directly into the Unity dashboard. It captures managed C# exceptions and native crashes from the IL2CPP runtime. The advantage is zero configuration beyond enabling the service. The disadvantage is less flexibility in custom metadata and alerting compared to Crashlytics.
Bugnet, Sentry, and Backtrace are alternatives that offer more control over data routing, custom grouping rules, and integration with external bug trackers. If your pipeline already uses Bugnet for bug tracking, its crash reporting SDK feeds crash data directly into your existing bug workflow without manual triage.
Symbolication: Making Stack Traces Readable
Raw crash reports from mobile devices contain memory addresses, not function names. Symbolication is the process of mapping those addresses back to your source code. Without it, a crash report is nearly useless.
On iOS, the compiler produces a dSYM (debug symbol) file for every build. This file contains the mapping between compiled addresses and source locations. You must upload the dSYM to your crash reporting service for every build you distribute — including TestFlight builds, App Store builds, and any ad-hoc builds sent to QA. If you miss a single dSYM upload, every crash from that build will be unsymbolicated.
On Android, the situation depends on your build configuration. If you use ProGuard or R8 for code shrinking, you need to upload the mapping.txt file. If your game includes native code (NDK or IL2CPP), you need to upload the native symbol files (.so files with debug symbols or a symbols.zip). Unity IL2CPP builds produce both managed and native stack frames, so you need both the mapping file and the native symbols.
Automate symbolication file uploads in your CI/CD pipeline. Never rely on developers remembering to upload them manually. A single forgotten upload means days of crashes that you cannot diagnose.
ANR Detection on Android
ANRs (Application Not Responding) are a distinctly Android problem. When your game’s main thread is blocked for more than five seconds while the user is interacting with it, Android shows a dialog asking the user to wait or force close. ANRs are not crashes — they are freezes — but Google Play treats them as seriously as crashes in your app’s quality metrics.
Common causes of ANRs in games include synchronous file I/O on the main thread during scene loads, blocking network calls on the main thread, garbage collection pauses in managed runtimes like Unity’s Mono backend, and lock contention between the render thread and the game thread. Firebase Crashlytics captures ANRs automatically on Android and provides the main thread stack trace at the time of the freeze.
The fix for most ANRs is moving blocking work off the main thread. Scene loading should be asynchronous. Network calls should never block the UI. File writes should happen on a background thread. In Unity, use async/await with LoadSceneAsync and UnityWebRequest instead of their synchronous counterparts.
Memory Pressure and iOS Jetsam Kills
iOS does not have swap space. When the system runs low on memory, it sends memory warnings to apps. If your game does not free enough memory in response, iOS terminates it via the jetsam mechanism. These terminations look like crashes to the player but they do not produce traditional crash reports. Instead, they appear as jetsam events in the device console log.
Firebase Crashlytics captures out-of-memory terminations on iOS as a separate category. Unity’s crash reporter also detects them. The challenge is that jetsam kills do not include a meaningful stack trace — the OS simply terminates the process. To diagnose them, you need to track memory usage over time and log the current memory footprint at regular intervals as a custom key in your crash reports.
On Android, low-end devices with 2-3 GB of RAM are equally prone to out-of-memory kills, especially when the game runs alongside background apps. The Android low memory killer daemon terminates apps based on priority, and a background game returning to the foreground may find its process was killed. This is not a crash but a cold restart that loses unsaved progress. Implement auto-save at frequent intervals to mitigate data loss.
Device Fragmentation on Android
Android device fragmentation is the single largest testing challenge for mobile games. There are thousands of active device models with different GPUs (Adreno, Mali, PowerVR), different driver versions, different OS versions (Android 10 through 15 in active use), and different RAM configurations. A crash that occurs on Samsung Galaxy A series devices with Mali GPUs may never reproduce on a Pixel with an Adreno GPU.
Crash reporting helps manage fragmentation by grouping crashes by device attributes. When a crash cluster appears, check the device breakdown first. If 90% of reports come from a specific GPU family, the fix is likely a shader or driver workaround. If crashes span all device types but only on Android 12, it is likely an OS-level API behavior change.
Maintain a list of target devices that covers the GPU and OS version matrix your players actually use. Firebase provides device catalog data showing which devices your players use most. Focus your manual testing on the top ten devices by install base, and let crash reporting catch issues on the long tail of devices you cannot physically test.
Privacy and Compliance
Crash reporting SDKs collect device data that falls under privacy regulations. Under GDPR, device identifiers like IDFV on iOS or Android ID can be considered personal data. Under Apple’s App Tracking Transparency framework, you need to declare data collection in your App Store privacy nutrition labels even if you do not track users across apps.
Firebase Crashlytics allows you to disable automatic data collection at initialization and enable it only after the user consents. This opt-in flow should be part of your first-launch experience if you operate in GDPR-regulated markets. Strip any personally identifiable information from custom log messages — do not log player email addresses, real names, or payment information as crash report metadata.
Integrating With Your Bug Tracker
Crash reports are most useful when they flow directly into your bug tracking workflow. Configure your crash reporting service to create bug reports automatically when a new crash cluster exceeds a threshold — for example, more than ten reports or more than 0.1% of daily sessions affected. The auto-created bug should include the grouped stack trace, affected device list, first and last occurrence dates, and a link back to the crash reporting dashboard for deeper analysis.
Bugnet supports direct integration with crash reporting data, linking crash groups to bug reports and tracking resolution status. When a developer marks a crash bug as fixed and deploys a new build, the crash reporting dashboard shows whether the crash rate dropped to zero in the new version, confirming the fix worked.
Upload your symbol files with every build. An unsymbolicated crash report is just random hexadecimal noise.