---
title: Error Analysis - iOS
description: How to use Contentsquare Error Analysis in your iOS apps
lastUpdated: 29 January 2026
source_url:
  html: https://docs.contentsquare.com/en/csq-sdk-ios/experience-analytics/error-analysis/
  md: https://docs.contentsquare.com/en/csq-sdk-ios/experience-analytics/error-analysis/index.md
---

Note

This feature is part of [Experience Monitoring ↗](https://contentsquare.com/platform/experience-monitoring/), which is only available on Enterprise plans or as an add-on to Pro plans. Contact your Customer Success Manager or [sales ↗](https://contentsquare.com/request-a-demo/) to learn more.

## Prerequisites

### Screen tracking implemented

Tracking will start at the 1st screenview event, it is required to have screen tracking implemented. Make sure to follow the [iOS Track](../track-screens/) screens sections.

### Reminder about User consent

If you are in the process of implementing the SDK for the 1st time (or choose to take this update as an opportunity to review your Privacy related implementation), make sure to follow the [iOS Privacy](../privacy/) section and use the [Opt-in API](../privacy/#opt-in) to get the user consent, otherwise no data will be collected.

## API errors

### Automatic collection

API errors automatically collects failed network requests that use `URLSession`.

### Disable automatic collection

Automatic collection can be disabled by setting `CSDisableAPIErrorsAutoCollection` to `YES` in the Info.plist.

### Add custom monitoring for specific network requests

The API errors automatically collects most network requests for your app. However, some requests might not be collected or you might use a different library to make network requests. In these cases, you can use the following API `HTTPMetric` to manually collect data.

* Swift

  ```swift
  guard let url = URL(string: "https://www.apple.com") else { return }
  let request: URLRequest = URLRequest(url: url)
  let metric = HTTPMetric(request: request)
  let session = URLSession(configuration: .default)
  let dataTask = session.dataTask(with: request) { (urlData, response, error) in
      if let httpResponse = response as? HTTPURLResponse {
          metric.setStatusCode(httpResponse.statusCode)
      }
      CSQ.trackNetworkMetric(metric)
  }
  dataTask.resume()
  ```

* Objective-C

  ```objective-c
  NSURL *url = [NSURL URLWithString:@"https://www.apple.com"];
  NSURLRequest *request = [[NSURLRequest alloc]initWithURL:url];
  HTTPMetric *metric = [[HTTPMetric alloc]initWithRequest:request];
  NSURLSession *session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration];
  NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
      NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
      [metric setStatusCode:httpResponse.statusCode];
      [CSQ trackNetworkMetric:metric];
  }];
  [task resume];
  ```

### Removing Personal Data in request URL path

By default, the API Errors feature collects the URL path of the failed API requests. To prevent the collection of Personal Data in the URL path, you can rewrite the request URL path with the `setURLMaskingPatterns` SDK API.

```swift
/// This API must be called at App launch.
public static func setURLMaskingPatterns(_ patterns: [String])
```

Replace a step of the path - meaning between two slashes (/) - containing Personal Data with a variable:

* `:user_id` becomes CS\_ANONYMIZED\_USER\_ID
* `:address` becomes CS\_ANONYMIZED\_ADDRESS

#### Example

```swift
ErrorAnalysis.setURLMaskingPatterns([
    "https://www.contentsquare.com/users/:user_id/address/:address"
])
```

| URL before masking | URL after masking |
| - | - |
| `https://www.contentsquare.com/users/123/address/castle+black` | `https://www.contentsquare.com/users/CS_ANONYMIZED_USER_ID/address/CS_ANONYMIZED_ADDRESS` |

### Validate API error integration

#### Validate API error collection is enabled

If in-app features are enabled, a log should appear indicating if API errors is enabled or disabled:

```plaintext
CSLIB ℹ️ Info: API Errors is enabled
```

#### Validate API error collection

If you have [logging enabled](https://docs.contentsquare.com/en/csq-sdk-ios/experience-analytics/in-app-features/#debugging-and-logging), you will see API errors:

* Displayed in [Contentsquare Log Visualizer](https://docs.contentsquare.com/en/csq-sdk-ios/experience-analytics/in-app-features/#viewing-logs-in-the-contentsquare-platform).
* As an Info log:

```plaintext
CSLIB ℹ️ Info: API Error - GET 401 https://api.client.com
```

### How API errors works

#### Initialization

The way our SDK works is by auto-starting with the application launch and automatically collects failed network requests that use `URLSession`.

#### Configuration

Once started, our SDK fetches its config from our servers. It will start collecting data from network events if the API errors setting is enabled in the config (this is handled by the Contentsquare team).

#### API errors collection

The SDK monitors only the API errors with response code equal or above 400, and generates analytics data. These events are then locally stored, and eventually sent to our servers in batches.

Warning

To make sure API errors occurring at app launch are correctly tracked, the session has to be tracked (included in tracked users and not opted-out) and a first screenview event has to be sent before. See [when to send your first screenview](../track-screens/#when-to-send-your-first-screenview) for more details.

#### Sending API errors data

For each network error, a new event will be sent in analytics and Session Replay data. Check the following sections to learn more about how data is processed and sent:

* [Analytics requests](../data-collection/#sending-data)
* [Session Replay requests](../session-replay#requests)

### API Troubleshooting Details

API errors troubleshooting details enables you to collect more information about API errors so you can troubleshoot errors faster.

With this feature you will be able to see three types of additional API error details in the Event Stream of Session Replay.

* The HTTP headers of the request and the response.
* The body (the data sent by the request or received in the response).
* The query parameters of the request endpoint (of the URL of the information you request for).

Note

This feature is only available for Experience Monitoring Mobile customers.\
Contact your CSM for more details on the validation and implementation process.

See [API Troubleshooting Details ↗](https://support.contentsquare.com/hc/en-us/articles/37271885035537) for more details.

### Collected data points

Only network calls with error (response code above 400) will be collected. Here is the list of data collected:

* URL (without query strings)
* HTTP method
* Response code
* Timestamp of the request
* Timestamp of the response
* HTTP headers of the request
* HTTP headers of the response
* HTTP body of the request
* HTTP body of the response
* Query parameters of the request endpoint

### Known limitations and recommendations

#### Automatic collection limitations

The auto collection doesn't work for the following methods:

```swift
func data(for request: URLRequest) async throws -> (Data, URLResponse)
func data(from url: URL) async throws -> (Data, URLResponse)
func upload(for request: URLRequest, from bodyData: Data) async throws -> (Data, URLResponse)
func upload(for request: URLRequest, fromFile fileURL: URL) async throws -> (Data, URLResponse)
func download(for request: URLRequest) async throws -> (URL, URLResponse)
func download(from url: URL) async throws -> (URL, URLResponse)


func downloadTask(withResumeData: Data) -> URLSessionDownloadTask
func downloadTask(withResumeData: Data, completionHandler: (URL?, URLResponse?, Error?) -> Void) -> URLSessionDownloadTask


func streamTask(withHostName: String, port: Int) -> URLSessionStreamTask
func streamTask(with: NetService) -> URLSessionStreamTask


func webSocketTask(with: URL) -> URLSessionWebSocketTask
func webSocketTask(with: URLRequest) -> URLSessionWebSocketTask
func webSocketTask(with: URL, protocols: [String]) -> URLSessionWebSocketTask
```

**Workaround:** For the `async` methods, use the corresponding Contentsquare methods:

```swift
try await URLSession.shared.cs.data(for: request)
try await URLSession.shared.cs.data(from: url)
try await URLSession.shared.cs.upload(for: request, from: data)
try await URLSession.shared.cs.upload(for: request, fromFile: file)
try await URLSession.shared.cs.download(for: request)
try await URLSession.shared.cs.download(from: url)
```

For other methods, use the custom monitoring APIs.

#### Conflict with Firebase Performance SDK on auto-collection

API errors is compatible with Firebase Performance auto-collection, but the HTTP body from the response won't be collected by the Error Analysis SDK.

**Workaround**: [Disable auto collection](#disable-automatic-collection) and use [API `HTTPMetric`](#add-custom-monitoring-for-specific-network-requests) to manually collect data.

It may also not be compatible with other network auto collection tools.

## Crash Reporter

### Setup Firebase Crashlytics compatibility mode

The Contentsquare Crash Reporter is compatible with [Firebase Crashlytics ↗](https://firebase.google.com/docs/crashlytics) as long as it is initialized first, otherwise some crashes can be missing in Crashlytics.

Use the `onCrashReporterStart()` API to launch Firebase Crashlytics after the Contentsquare Crash Reporter starts:

* Swift

  ```swift
  CSQ.onCrashReporterStart { _ in
    FirebaseApp.configure()
  }
  ```

* Objective-C

  ```objective-c
  [CSQ onCrashReporterStart:^(BOOL _) {
    [FIRApp configure];
  }];
  ```

### Upload dSYMs

*"When Xcode compiles your source code into machine code, it generates a list of symbols in your app — class names, global variables, and method and function names. These symbols correspond to the file and line numbers where they're defined; this association creates a debug symbol"* [See Apple's documentation for more details ↗](https://developer.apple.com/documentation/xcode/building-your-app-to-include-debugging-information/).

When an app crashes, the operating system collects diagnostic information about what the app was doing at the time of crash. Some of the most important parts of the crash report are presented as hexadecimal addresses. To translate those addresses into readable function names and line numbers from your source code, a process called symbolication is used. [See Apple's documentation for more details ↗](https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report/).

In order to symbolicate the crashes reported by a specific version of your app and make them readable, you need to provide the symbol files (dSYMs) that were generated when your app was built.

#### Build your app with dSYMs

Make sure Xcode is generating dSYMs for your app:

1. Open your project in Xcode.
2. Select the project file in the Xcode Navigator.
3. Select your main target.
4. Select the `Build Settings` tab and click `All` to show all the build settings.
5. Filter by `Debug Information Format`.
6. Set `Debug Information Format` to `DWARF with dSYM File` for all the build types you want to generate dSYMs.
7. Rebuild your main target.

#### Locate dSYMs

##### Download dSYMs from the App Store

If you build your main target using bitcode (`Bitcode Enabled` turned on in build settings) and you uploaded your app's symbols to the App Store, you need to download the dSYMs from the App Store:

1. Log in to [App Store Connect ↗](https://appstoreconnect.apple.com/login), then select `My Apps`.
2. Select your app from the grid.
3. Select the build you want to download a dSYM for.
4. Click `Build Details` > `Download dSYM`.

In case you use bitcode to build your main target but you didn't upload your dSYMs to the App Store, you need to [find your dSYMs on your local machine](#find-dsyms-on-your-local-machine) and [restore hidden symbols using the BCSymbolMaps](#restore-hidden-symbols-using-bcsymbolmaps) Xcode generates.

##### Find dSYMs on your local machine

You can find the dSYMs in the `.xcarchive` directory on disk:

1. In Xcode, open the Organizer window (*Window -> Organizer*).
2. Select your app from the list.
3. Control-click an archive and select `Show in Finder`.
4. A Finder window should appear. Control-click the `xcarchive` package and select `Show Package Contents`.
5. There should be a dSYMs directory that contains the dSYMs generated in Xcode's archiving process. If you use the `Download Debug Symbols` option from Xcode's organizer, the recompiled bitcode dSYMs are also downloaded to this directory.

#### Restore hidden symbols using BCSymbolMaps

Restoring hidden symbols using BCSymbolMaps is only required if you built your main target using bitcode (`Bitcode Enabled` turned on in build settings). If you used bitcode but downloaded the dSYMs from the App Store, the dSYMs will be recompiled and you can skip this step.

To restore hidden symbols you can run the following command:

```shell
dsymutil -symbol-map /path/to/archive/BCSymbolMaps /path/to/dsym.dSYM
```

#### Get project ID

1. Login to the Contentsquare platform on [https://app.contentsquare.com ↗](https://app.contentsquare.com)
2. Make sure to be on the right project
3. The project ID can be found in the URL query parameter `project`: `https://app.contentsquare.com/#/{MODULE_NAME}?project={PROJECT_ID}&hash={HASH}]`

#### Get project credentials

Follow the dedicated documentation from the Help Center to get the **client ID** and **client Secret**: [How to create API credentials ↗](https://support.contentsquare.com/hc/en-us/articles/9292880837660).

#### Use script to upload dSYMs

To upload dSYMs to Error Analysis you need to use the provided `upload-symbols` script. You need to provide the path where the dSYM files are located as a positional argument, and the Project ID, Client ID and Client Secret either as keyword arguments or set them as environment variables.

Additionally, you can use a proxy by specifying the proxy URL. Print more detailed logs by using the `--verbose` flag.

| Key | Environment Key |
| - | - |
| --project-id | ERROR\_ANALYSIS\_PROJECT\_ID |
| --client-id | ERROR\_ANALYSIS\_CLIENT\_ID |
| --client-secret | ERROR\_ANALYSIS\_CLIENT\_SECRET |
| --proxy | ERROR\_ANALYSIS\_PROXY\_URL |

If both are provided, the keyword arguments will prevail over the environment variables.

#### Set up Xcode to automatically upload dSYM files

The following steps describe how to configure Xcode to automatically upload your dSYMs whenever you build your app.

1. Open your project's Xcode workspace, then select its project file in the left Project navigator.

2. From the TARGETS list, select your main build target.

3. Click the **Build Phases** tab, then complete the following steps so that Xcode can process your dSYMs and upload the files.

   1. Click + > **New Run Script Phase**. Make sure this new Run Script phase is your project's last build phase; otherwise, dSYMs might not be ready.
   2. Expand the new **Run Script** section.
   3. In the script field (located under the Shell label), add the following run script.

* Swift Package Manager

  If you are using SPM to integrate the Error Analysis SDK, the `upload-symbols` script will be located in the SPM checkout path for the SDK. Copy the following script.

  ```shell
  # Only upload symbols for App Store build.
  # Replace `Release` with the configuration used when uploading to the App Store.
  if [ "${CONFIGURATION}" != "Release" ]; then
  exit 0
  fi
  ${BUILD_DIR%Build/*}SourcePackages/checkouts/CS_iOS_SDK/scripts/upload-symbols "${DWARF_DSYM_FOLDER_PATH}" --project-id "PROJECT_ID" --client-id "CLIENT_ID" --client-secret "CLIENT_SECRET"
  ```

* Other dependency managers

  If you are using CocoaPods or you are manually integrating the Error Analysis SDK, you will need to download the `upload-symbols` script from the latest SDK release.

  1. Go to the [CS\_iOS\_SDK releases page ↗](https://github.com/ContentSquare/CS_iOS_SDK/releases).
  2. Click `Show all assets` located at the bottom of the Assets list of the latest release.
  3. Click `upload-symbols-script.zip`.
  4. Unzip the script.
  5. Move the script to your project root, same location as xxxx.xcodeproj.

  Copy the following script.

  ```shell
  # Only upload symbols for App Store build.
  # Replace `Release` with the configuration used when uploading to the App Store.
  if [ "${CONFIGURATION}" != "Release" ]; then
    exit 0
  fi
  ${SRCROOT}/upload-symbols "${DWARF_DSYM_FOLDER_PATH}" --project-id "PROJECT_ID" --client-id "CLIENT_ID" --client-secret "CLIENT_SECRET"
  ```

In the *Input Files* section, make sure you have the paths for the locations of the following files:

```plaintext
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}
```

```plaintext
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME}
```

```plaintext
${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist
```

```plaintext
$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH)
```

Make sure *User Script Sandboxing* is set to NO in Xcode Build Settings. if you don't want to disabled it, you need to add the paths of all your dSYMs files one by one in *Input Files*.

#### Use fastlane to upload dSYMs

The instructions require fastlane `1.93.0` or later.

1. Add fastlane plugin to your project:

   1. Run `fastlane add_plugin fastlane-plugin-contentsquare`.
   2. Select `Git URL` and input [https://github.com/ContentSquare/contentsquare-fastlane-plugin.git ↗](https://github.com/ContentSquare/contentsquare-fastlane-plugin.git). See [fastlane Plugins ↗](https://docs.fastlane.tools/plugins/using-plugins/) for more information.

2. Call fastlane plugin in your build process: `upload_symbols_to_error_analysis(project_id: your_project_id, client_id: "your_client_id", client_secret: "your_client_secret")`

Note

You need to use `bundle exec fastlane [lane]` to run fastlane.

### Validate crash reporter integration

#### Validate crash collection is activated

Enabling crash reporting will conflict with any attached debuggers, so make sure a debugger isn't attached when you crash the app. In case a debugger is attached to the device, Crash Reporter won't be initialized and a log will be printed in the console:

```plaintext
CSLIB ℹ️ Info: Debugger present, crash reporter is not initialized
```

To test if Crash Reporter is working properly, you first need to disconnect your test device or simulator from Xcode debugger:

* Tap on the *Edit scheme...* option of your current scheme
* Disable the *Debug executable* option in your scheme configuration.
* Build and run your current scheme.

If Crash Reporter is successfully initialized when you launch your application, you should see a log printed in the console:

```plaintext
CSLIB ℹ️ Info: Crash reporter is initialized
```

Alternatively, you can detach your application from Xcode debugger by stopping it after it is launched. This way Crash Reporter will be initialized and will start reporting crashes, but you won't be able to see the logs printed in the console:

* Build and run your current scheme.
* Wait until the app is up and running.
* Click Stop running the scheme.
* Open the app directly from your test device or simulator.

#### Validate crash reporting

Run your application and force a crash (you can do it by adding a `fatalError()` in your code). Launch the application again using Xcode and you should see a log printed in the console that indicates that a crash has been detected and sent:

```plaintext
CSLIB ℹ️ Info: Crash event detected and sent for userID: <user-id>, session: <session-number> on screen: <screen-number> - crashID: <crash-id>
```

### How Crash Reporter works

#### Initialization

Crash Reporter is started automatically and begins to report crashes when your application is launched.

#### Configuration

Once started, our SDK fetches its configuration from our servers. It will start reporting crashes if the Crash Reporter setting is enabled (this is handled by the Contentsquare team).

#### Reporting

When a crash occurs, a report is created and stored locally in the device. Once the app is launched again, the report is sent to our servers and then removed from the local storage.

Warning

To make sure crashes occurring at app launch are correctly tracked, the session has to be tracked (included in tracked users and not opted-out) and a first screenview event has to be sent before. See [when to send your first screenview](../track-screens/#when-to-send-your-first-screenview) for more details.

#### Sending crash data

For each crash, a new event will be sent to analytics and Session Replay data when the app is launched again after the crash occurred and the network conditions allow for the server to be reached.

Our requests use [`lowPriority` ↗](https://developer.apple.com/documentation/foundation/urlsessiontask/1411509-lowpriority).

### Collected data points

Crash Reporter handles multiple types of crashes, including:

* Mach kernel exceptions
* Fatal signals
* C++ exceptions
* Objective-C exceptions

For each crash we collect information of the application, system, process, threads, stack traces and some other events metadata you can find in [collected data points](../data-collection/#collected-data-points).

### Known limitations and recommendations

#### Compatibility with other crash reporters

Beyond Firebase Crashlytics (see [Setup Firebase Crashlytics compatibility mode](#setup-firebase-crashlytics-compatibility-mode)), the Contentsquare Crash Reporter is not compatible with other crash reporters. For more details, reach out to your Contentsquare contact.

## WebView errors

Errors occurring in web pages loaded in WebViews can be collected if Webview tracking is set up in your app.

See 📚 [Webview Tracking implementation](https://docs.contentsquare.com/en/webview-tracking-tag/).

Once WebView tracking is implemented, errors collection can be set up.

See 📚 [Errors (in WebView)](https://docs.contentsquare.com/en/webview-tracking-tag/error-analysis/)

## Impact on Performance

We always strive to be non-intrusive, and transparent to the developers of the client app. We apply this rule on the performance as well. These are the technical specifics we can share on performance, if you have any questions feel free to reach out to us.

The following performance results were obtained under the following conditions:

| Condition | Value |
| - | - |
| Device model | iPhone 11 Pro 64GB |
| iOS version | 16.5 |
| Test App built using Xcode version | 15.3 |
| Test App built with Swift version | 5.8 |

Note

The numbers provided below will vary depending on the user's device, iOS version, SDK version, as well as if you use Swift or not, which Swift version you use if you do, if you enabled bitcode or not and which options you used when building your IPA for App Store distribution.

| Property | Value |
| - | - |
| Max RAM usage | <2MB |
| Max SDK CPU peak on event | <2% |
