---
title: iOS Crash Reporting and Error Tracking
description: Set up Error Tracking for your iOS projects.
breadcrumbs: >-
  Docs > RUM & Session Replay > Error Tracking for Web and Mobile Applications >
  Mobile Crash Reporting > iOS Crash Reporting and Error Tracking
---

# iOS Crash Reporting and Error Tracking

## Overview{% #overview %}

Enable iOS Crash Reporting and Error Tracking to get comprehensive crash reports and error trends with Real User Monitoring. With this feature, you can access:

- Aggregated iOS crash dashboards and attributes
- Symbolicated iOS crash reports
- Trend analysis with iOS error tracking

In order to symbolicate your stack traces, find and upload your `.dSYM` files to Datadog. Then, verify your configuration by running a test crash and restarting your application.

Your crash reports appear in [**Error Tracking**](https://app.datadoghq.com/rum/error-tracking).

## Setup{% #setup %}

If you have not set up the iOS SDK yet, follow the [in-app setup instructions](https://app.datadoghq.com/rum/application/create) or see the [iOS RUM setup documentation](https://docs.datadoghq.com/real_user_monitoring/ios).

### Add crash reporting{% #add-crash-reporting %}

To enable Crash Reporting, make sure to also enable [RUM](https://docs.datadoghq.com/real_user_monitoring/ios). Then, add the package according to your dependency manager and update your initialize snippet.

{% tab title="CocoaPods" %}
You can use [CocoaPods](https://cocoapods.org/) to install `dd-sdk-ios`:

```
pod 'DatadogCrashReporting'
```

{% /tab %}

{% tab title="Swift Package Manager (SPM)" %}
To integrate using Apple's Swift Package Manager, add the following as a dependency to your `Package.swift`:

```swift
.package(url: "https://github.com/Datadog/dd-sdk-ios.git", .upToNextMajor(from: "3.0.0"))
```

In your project, link the following libraries:

```
DatadogCrashReporting
```

{% /tab %}

{% tab title="Carthage" %}
You can use [Carthage](https://github.com/Carthage/Carthage) to install `dd-sdk-ios`:

```
github "DataDog/dd-sdk-ios"
```

In Xcode, link the following frameworks:

```
DatadogCrashReporting.xcframework
```

{% /tab %}

Update your initialization snippet to include Crash Reporting:

```swift
import DatadogCore
import DatadogCrashReporting

Datadog.initialize(
  with: Datadog.Configuration(
    clientToken: "<client token>",
    env: "<environment>",
    service: "<service name>"
  ), 
  trackingConsent: trackingConsent
)

CrashReporting.enable()
```

### Add app hang reporting{% #add-app-hang-reporting %}

App hangs are an iOS-specific type of error that happens when the application is unresponsive for too long.

By default, app hangs reporting is **disabled**, but you can enable it and set your own threshold to monitor app hangs that last more than a specified duration by using the `appHangThreshold` initialization parameter. A customizable threshold allows you to find the right balance between fine-grained and noisy observability. See [Configure the app hang threshold](https://docs.datadoghq.com/real_user_monitoring/error_tracking/mobile/ios/?tab=cocoapods#configure-the-app-hang-threshold) for more guidance on what to set this value to.

App hangs are reported through the RUM iOS SDK (not through [Logs](https://docs.datadoghq.com/logs/log_collection/ios)).

When enabled, any main thread pause that is longer than the specified `appHangThreshold` is considered a "hang" in [**Error Tracking**](https://app.datadoghq.com/rum/error-tracking). There are two types of hangs:

- **Fatal app hang**: How a hang gets reported if it never gets recovered and the app is terminated. Fatal app hangs are marked as a "Crash" in Error Tracking and the RUM explorer.

  {% image
     source="https://datadog-docs.imgix.net/images/real_user_monitoring/error_tracking/ios-fatal-app-hang-1.f2680313f133792d11e682c5ef238d7e.png?auto=format"
     alt="A fatal app hang in the RUM Error side panel." /%}

- **Non-fatal app hang**: How a hang gets reported if the app recovers from a relatively short hang and continues running. Non-fatal app hangs do not have a "Crash" mark on them in Error Tracking and the RUM explorer.

  {% image
     source="https://datadog-docs.imgix.net/images/real_user_monitoring/error_tracking/ios-non-fatal-app-hang-1.473882e837695c5affa91d45a3920e7b.png?auto=format"
     alt="A non-fatal app hang in the RUM Error side panel." /%}

#### Enable app hang monitoring{% #enable-app-hang-monitoring %}

To enable app hang monitoring:

1. [Enable Crash Reporting](https://docs.datadoghq.com/real_user_monitoring/error_tracking/mobile/ios/?tab=cocoapods#add-crash-reporting)

1. Update the initialization snippet with the `appHangThreshold` parameter:

   ```swift
   RUM.enable(
       with: RUM.Configuration(
           applicationID: "<rum application id>",
           appHangThreshold: 0.25
       )
   )
   ```

1. Set the `appHangThreshold` parameter to the minimal duration you want app hangs to be reported. For example, enter `0.25` to report hangs lasting at least 250 ms. See [Configure the app hang threshold](https://docs.datadoghq.com/real_user_monitoring/error_tracking/mobile/ios/?tab=cocoapods#configure-the-app-hang-threshold) for more guidance on what to set this value to.

Make sure you follow the steps below to get [deobfuscated stack traces](https://docs.datadoghq.com/real_user_monitoring/error_tracking/mobile/ios/?tab=cocoapods#get-deobfuscated-stack-traces).

#### Configure the app hang threshold{% #configure-the-app-hang-threshold %}

- Apple only considers hangs lasting more than 250 ms in their hang rate metrics in Xcode Organizer. Datadog recommends starting with a similar value for the `appHangThreshold` (in other words, set it to `0.25`) and then lowering it or increasing it incrementally to find the right setup.

- To filter out most of the noisy hangs, we recommend settling on an `appHangThreshold` between 2 and 3 seconds.

- The minimum value the `appHangThreshold` option can be set to is `0.1` seconds (100 ms). However, setting the threshold to such small values may lead to an excessive reporting of hangs.

- The SDK implements a secondary thread for monitoring app hangs. To reduce CPU utilization, it tracks hangs with a tolerance of 2.5%, which means some hangs that last close to the `appHangThreshold` may not be reported.

#### Compute the hang rate of your application{% #compute-the-hang-rate-of-your-application %}

[Xcode Organizer](https://developer.apple.com/documentation/xcode/analyzing-responsiveness-issues-in-your-shipping-app#View-your-apps-hang-rate) and [MetricKit](https://developer.apple.com/documentation/metrickit/mxhangdiagnostic) both provide a hang rate metric defined as "the number of seconds per hour that the app is unresponsive, while only counting periods of unresponsiveness of more than 250 ms."

To compute a similar hang rate on Datadog, make sure:

1. That app hang reporting is enabled.
1. That the app hang threshold is equal or below 250 ms.
1. That the `@error.category` and `@freeze.duration` attribute reported on your app hangs errors in RUM are available in your facets (this should be the case by default. If it's not, you can manually [create facets](https://docs.datadoghq.com/real_user_monitoring/explorer/search/#facets)).

If all these prerequisites are met, then create a new [Timeseries widget](https://docs.datadoghq.com/dashboards/widgets/timeseries) on a Dashboard or a Notebook, and paste the following snippet in the JSON tab of your widget, under the "Graph your data" section:

{% image
   source="https://datadog-docs.imgix.net/images/real_user_monitoring/error_tracking/json-tab.1d0152d971838bf65c3bc4f5423c1d71.png?auto=format"
   alt="The modal to edit the configuration of a widget, with the JSON tab open" /%}

{% collapsible-section %}
##### JSON snippet of the hang rate widget

```json
{
    "title": "Hang Rate",
    "type": "timeseries",
    "requests": [
        {
            "formulas": [
                {
                    "number_format": {
                        "unit": {
                            "type": "custom_unit_label",
                            "label": "seconds/hour"
                        }
                    },
                    "formula": "(query2 * 3600000000000) / query1"
                }
            ],
            "queries": [
                {
                    "name": "query2",
                    "data_source": "rum",
                    "search": {
                        "query": "@type:error @error.category:\"App Hang\" @freeze.duration:>=250000000 @session.type:user"
                    },
                    "indexes": [
                        "*"
                    ],
                    "group_by": [
                        {
                            "facet": "@application.name",
                            "limit": 10,
                            "sort": {
                                "aggregation": "sum",
                                "order": "desc",
                                "metric": "@freeze.duration"
                            },
                            "should_exclude_missing": true
                        },
                        {
                            "facet": "version",
                            "limit": 10,
                            "sort": {
                                "aggregation": "sum",
                                "order": "desc",
                                "metric": "@freeze.duration"
                            },
                            "should_exclude_missing": true
                        }
                    ],
                    "compute": {
                        "aggregation": "sum",
                        "metric": "@freeze.duration",
                        "interval": 3600000
                    },
                    "storage": "hot"
                },
                {
                    "name": "query1",
                    "data_source": "rum",
                    "search": {
                        "query": "@type:session @session.type:user"
                    },
                    "indexes": [
                        "*"
                    ],
                    "group_by": [
                        {
                            "facet": "@application.name",
                            "limit": 10,
                            "sort": {
                                "aggregation": "sum",
                                "order": "desc",
                                "metric": "@session.time_spent"
                            },
                            "should_exclude_missing": true
                        },
                        {
                            "facet": "version",
                            "limit": 10,
                            "sort": {
                                "aggregation": "sum",
                                "order": "desc",
                                "metric": "@session.time_spent"
                            },
                            "should_exclude_missing": true
                        }
                    ],
                    "compute": {
                        "aggregation": "sum",
                        "metric": "@session.time_spent",
                        "interval": 3600000
                    },
                    "storage": "hot"
                }
            ],
            "response_format": "timeseries",
            "style": {
                "palette": "dog_classic",
                "order_by": "values",
                "line_type": "solid",
                "line_width": "normal"
            },
            "display_type": "line"
        }
    ],
    "yaxis": {
        "include_zero": true,
        "scale": "sqrt"
    },
    "markers": [
        {
            "value": "y > 12000000000",
            "display_type": "error dashed"
        },
        {
            "value": "6000000000 < y < 12000000000",
            "display_type": "warning dashed"
        },
        {
            "value": "0 < y < 6000000000",
            "display_type": "ok dashed"
        }
    ]
}
```

{% /collapsible-section %}

#### Disable app hang monitoring{% #disable-app-hang-monitoring %}

To disable app hang monitoring, update the initialization snippet and set the `appHangThreshold` parameter to `nil`.

### Add watchdog terminations reporting{% #add-watchdog-terminations-reporting %}

In the Apple ecosystem, the operating system employs a watchdog mechanism to monitor the health of applications, and terminates them if they become unresponsive or consume excessive resources like CPU and memory. These Watchdog Terminations are fatal and not recoverable (more details in the official [Apple documentation](https://developer.apple.com/documentation/xcode/addressing-watchdog-terminations)).

By default, watchdog terminations reporting is **disabled**, but you can enable it by using the `trackWatchdogTerminations` initialization parameter.

Watchdog terminations are reported through the RUM iOS SDK only (not through [Logs](https://docs.datadoghq.com/logs/log_collection/ios)).

When enabled, a watchdog termination is reported and attached to the previous RUM Session on the next application launch, based on heuristics:

- The application was not upgraded in the meantime,

- And it did not call either `exit`, or `abort`,

- And it did not crash, either because of an exception, or because of a fatal [app hang](https://docs.datadoghq.com/real_user_monitoring/error_tracking/mobile/ios/?tab=cocoapods#add-app-hang-reporting),

- And it was not force-quitted by the user,

- And the device did not reboot (which includes upgrades of the operating system).

{% image
   source="https://datadog-docs.imgix.net/images/real_user_monitoring/error_tracking/ios-watchdog-termination-1.037511936147ff8206a9163e5cafd306.png?auto=format"
   alt="A watchdog termination in the RUM Error side panel." /%}

#### Enable watchdog terminations reporting{% #enable-watchdog-terminations-reporting %}

To enable watchdog terminations reporting:

1. [Enable Crash Reporting](https://docs.datadoghq.com/real_user_monitoring/error_tracking/mobile/ios/?tab=cocoapods#add-crash-reporting)

1. Update the initialization snippet with the `trackWatchdogTerminations` flag:

   ```swift
   RUM.enable(
       with: RUM.Configuration(
           applicationID: "<rum application id>",
           trackWatchdogTerminations: true
       )
   )
   ```

#### Troubleshoot watchdog terminations{% #troubleshoot-watchdog-terminations %}

When an application is terminated by the iOS Watchdog, it doesn't get any termination signal. As a result of this lack of a termination signal, watchdog terminations do not contain any stack trace. To troubleshoot watchdog terminations, Datadog recommends looking at the [vitals](https://docs.datadoghq.com/real_user_monitoring/application_monitoring/mobile_vitals?tab=ios#telemetry) of the parent RUM View (CPU Ticks, Memory).

#### Disable watchdog terminations reporting{% #disable-watchdog-terminations-reporting %}

To disable watchdog terminations reporting, update the initialization snippet and set the `trackWatchdogTerminations` parameter to `false`.

## Get deobfuscated stack traces{% #get-deobfuscated-stack-traces %}

Mapping files are used to deobfuscate stack traces, which helps in debugging errors. Using a unique build ID that gets generated, Datadog automatically matches the correct stack traces with the corresponding mapping files. This ensures that regardless of when the mapping file was uploaded (either during pre-production or production builds), the correct information is available for efficient QA processes when reviewing crashes and errors reported in Datadog.

For iOS applications, the matching of stack traces and symbol files relies on their `uuid` field.

### List uploaded .dSYMs{% #list-uploaded-dsyms %}

See the [RUM Debug Symbols](https://app.datadoghq.com/source-code/setup/rum) page to view all uploaded symbols.

### Symbolicate crash reports{% #symbolicate-crash-reports %}

Crash reports are collected in a raw format and mostly contain memory addresses. To map these addresses into legible symbol information, Datadog requires .`dSYM` files, which are generated in your application's build or distribution process.

### Find your .dSYM file{% #find-your-dsym-file %}

Every iOS application produces `.dSYM` files for each application module. These files minimize an application's binary size and enable faster download speed. Each application version contains a set of `.dSYM` files.

Xcode exports `.dSYM` files to `$DWARF_DSYM_FOLDER_PATH` at the end of your application's build. Ensure that the `DEBUG_INFORMATION_FORMAT` build setting is set to **DWARF with dSYM File**. By default, Xcode projects only set `DEBUG_INFORMATION_FORMAT` to **DWARF with dSYM File** for the Release project configuration.

### Upload your .dSYM file{% #upload-your-dsym-file %}

By uploading your `.dSYM` file to Datadog, you gain access to the file path and line number of each frame in an error's related stack trace.

Once your application crashes and you restart the application, the iOS SDK uploads a crash report to Datadog.

**Note**: Re-uploading a source map does not override the existing one if the version has not changed.

### Use Datadog CI to upload your .dSYM file{% #use-datadog-ci-to-upload-your-dsym-file %}

You can use the command line tool [@datadog/datadog-ci](https://www.npmjs.com/package/@datadog/datadog-ci) to upload your `.dSYM` file:

```sh
export DATADOG_API_KEY="<API KEY>"

// if you have a zip file containing dSYM files
npx @datadog/datadog-ci dsyms upload appDsyms.zip

// if you have a folder containing dSYM files
npx @datadog/datadog-ci dsyms upload /path/to/appDsyms/
```

**Notes**:

- To configure the tool using the EU endpoint, set the `DATADOG_SITE` environment variable to `datadoghq.eu`. To override the full URL for the intake endpoint, define the `DATADOG_DSYM_INTAKE_URL` environment variable.
- The `datadog-ci dsyms upload` command runs only on macOS.

Alternatively, if you use Fastlane or GitHub Actions in your workflows, you can leverage these integrations instead of `datadog-ci`:

### Use Fastlane plugin to upload your .dSYM file{% #use-fastlane-plugin-to-upload-your-dsym-file %}

The Fastlane plugin helps you upload `.dSYM` files to Datadog from your Fastlane configuration.

1. Add [`fastlane-plugin-datadog`](https://github.com/DataDog/datadog-fastlane-plugin) to your project.

   ```sh
   fastlane add_plugin datadog
   ```

1. Configure Fastlane to upload your symbols.

   ```ruby
   # download_dsyms action feeds dsym_paths automatically
   lane :upload_dsym_with_download_dsyms do
     download_dsyms
     upload_symbols_to_datadog(api_key: "datadog-api-key")
   end
   ```

For more information, see [`fastlane-plugin-datadog`](https://github.com/DataDog/datadog-fastlane-plugin).

### Use GitHub Actions to upload your .dSYM file{% #use-github-actions-to-upload-your-dsym-file %}

The [Datadog Upload dSYMs GitHub Action](https://github.com/marketplace/actions/datadog-upload-dsyms) allows you to upload your symbols in your GitHub Action jobs:

```yml
name: Upload dSYM Files

jobs:
  build:
    runs-on: macos-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Generate/Download dSYM Files
        uses: ./release.sh

      - name: Upload dSYMs to Datadog
        uses: DataDog/upload-dsyms-github-action@v1
        with:
          api_key: ${{ secrets.DATADOG_API_KEY }}
          site: datadoghq.com
          dsym_paths: |
            path/to/dsyms/folder
            path/to/zip/dsyms.zip
```

For more information, see [dSYMs commands](https://github.com/DataDog/datadog-ci/blob/master/packages/datadog-ci/src/commands/dsyms/README.md).

## Limitations{% #limitations %}

- dSYM files are limited in size to **2 GB** each.
- Symbols are not supported for simulators. Symbols are only available for crashes on physical iOS and tvOS devices.

## Test your implementation{% #test-your-implementation %}

To verify your iOS Crash Reporting and Error Tracking configuration, issue a crash in your RUM application and confirm that the error appears in Datadog.

1. Run your application on an iOS simulator or a real device. Ensure that the debugger is not attached. Otherwise, Xcode captures the crash before the iOS SDK does.

1. Execute the code containing the crash:

   ```swift
   func didTapButton() {
     fatalError("Crash the app")
   }
   ```

1. After the crash happens, restart your application and wait for the iOS SDK to upload the crash report in [**Error Tracking**](https://app.datadoghq.com/rum/error-tracking).

**Note:** RUM supports symbolication of system symbol files for iOS v14+ arm64 and arm64e architecture.

## Further Reading{% #further-reading %}

- [Source code for dd-sdk-ios](https://github.com/DataDog/dd-sdk-ios)
- [Introducing iOS Crash Reporting and Error Tracking](https://datadoghq.com/blog/ios-crash-reporting-datadog/)
- [Learn about Error Tracking](https://docs.datadoghq.com/real_user_monitoring/error_tracking/)
