# Upload debugging symbols from CI/CD pipelines

> Automatically upload symbol files from CI/CD pipelines to help diagnose issues in your project.

Automatically upload your project's debug symbols from CI/CD pipelines so that Unity Diagnostics can display human-readable crash reports with function names, file names, and line numbers.

> **Note:**
>
> You can also upload debugging symbols through [the Unity Dashboard](/cloud/developer-data/upload-symbol-files.md).

## CI/CD pipeline automatic upload process

When you upload debugging symbols from a CI/CD pipeline, the following process automatically occurs:

1. Your CI pipeline authenticates with a service account and runs one of the provided upload scripts.
2. The script validates the service account's credentials and fetches a time-limited token.
3. The script uses the `usymtool` CLI bundled with the Unity Editor to upload symbol files to cloud storage.

```mermaid title="Debugging symbols upload process"
graph LR
    A["Your CI Runner<br/><br/>Runs upload script"] --> B["Unity Services Gateway<br/><br/>Validates service account credentials<br/>Returns auth token"]
    B --> C["Symbol Storage (GCS)<br/><br/>The <code>usymtool</code> uploads here via pre-signed URLs"]
```

The scripts handle the complete upload workflow:

1. It validates that all required paths exist, including the `usymtool` binary symbol files, and IL2CPP output.
2. It generates a fresh upload token from the Unity Services API using your service account credentials.
3. It derives the correct `usymtool` binary path, symbol path, IL2CPP paths, and flags for your target platform.
4. It runs `usymtool` with the appropriate arguments, passing the token via the `USYM_UPLOAD_AUTH_TOKEN` environment variable.

You don't need to track when tokens expire. Each token is valid for seven days, and the scripts use the token API to automatically generate a fresh token on every run.

## Prerequisites

Before you begin, make sure you meet the following requirements:

* You use Unity 6.2 or later.
* You have a Unity project with **Diagnostics Data enabled** in your **Project Settings**. You can also manage this setting per build through **Build Profiles**.
* You have either the Unity Editor installed on your build machine or CI runner, or the `usymtool` binary extracted from it.
* You use a build pipeline that produces one of the following types of symbol files:
  * .dSYM on macOS and iOS
  * .so on Android
  * .pdb on Windows

Depending on which platform you use, you also need to meet additional requirements:

* For macOS, confirm that you have Python 3 installed on your build machine. Most macOS systems have Python 3 pre-installed.
* For Android, you need to configure one or both of the following settings in the Editor:
  * In **Player Settings** > **Android** > **Publishing Settings**, turn on **Create symbols.zip**.
  * In **Build Profiles**, turn on **Debug Symbols**.
  > **Important:**
  >
  > If you don't turn on these settings, Unity still produces .so files in the default symbol path, but they don't contain any debug data to help with symbolication upon upload.

## Create a service account

To create a service account, follow these steps:

1. In the [Unity Dashboard](https://cloud.unity.com), follow the instructions to [create a service account](/cloud/accounts/create-service-account.md).
2. In the **Project roles** section, select **Manage project roles**.
3. Select your project.
4. In the **LiveOps** menu, select **Observability Symbols Uploader**.

After you add the required role, the service account is configured to work with the `usymtool` script.

## Download the usymtool script

To download the `usymtool` script, follow these steps:

1. In the [Unity Dashboard](https://cloud.unity.com), open your project.
2. In your project overview, select **View Diagnostics**.
3. Select **Debugging Symbols**.
4. Select **Download CI script**.
5. Select the corresponding script for your host operating system.

After you select the script, the script file is downloaded to your default download location.

## Configure and run the upload script

After you download the `usymtool` script, you need to configure it for your operating system.

Both the macOS and Windows scripts automatically derive the following platform-specific paths:

* The `usymtool` binary location
* Symbol files
* IL2CPP directories
* Log path
* File filters

> **Important:**
>
> If your project layout differs from the defaults, then refer to [Override derived paths](#override-derived-paths) for additional configuration information.

To configure and run the upload script, follow the instructions for your operating system:

* [macOS](#configure-usymtool.sh-for-the-macos-host-platform)
* [Windows](#configure-usymtool.ps1-for-the-windows-host-platform)

### Configure usymtool.sh for the macOS host platform

Before you configure the upload script, make sure you have the following information:

* Your Unity Project ID. To find your Unity Project ID in the [Unity Dashboard](https://cloud.unity.com), select your project and go to **Settings**.
* The Authorization header that you copied in the [previous step](#create-a-service-account).

> **Note:**
>
> If the copied value for Authorization header includes `Authorization:` at the beginning, then remove that prefix.

To configure `usymtool.sh` for the macOS host platform, follow these steps:

1. Open the script.
2. Fill in the **USER CONFIGURATION** section with the following information.

> **Important:**
>
> Don't add `-projectId` to the script. The script uses `usymtool`'s pre-signed URL upload mode and doesn't have a `-projectId` flag. If the flag is present, the script switches to a different upload mode that requires Google Cloud Storage credentials and ignores your service account token.

| Variable                            | Platforms  | Description                                                                    | Example                                               |
| ----------------------------------- | ---------- | ------------------------------------------------------------------------------ | ----------------------------------------------------- |
| `PLATFORM`                          | All        | Target platform                                                                | `"ios"`, `"macos"`, or `"android"`                    |
| `USE_IL2CPP`                        | All        | Whether the build uses the IL2CPP scripting backend                            | `true`                                                |
| `UNITY_PROJECT_ID`                  | All        | Your Unity Project ID, as found on the **Settings** tab in the Unity Dashboard | `"12345678-abcd-1234-5678-12345678abcd"`              |
| `UNITY_SERVICE_ACCOUNT_AUTH_HEADER` | All        | Authorization header copied in the [previous step](#create-a-service-account)  | `"Basic MmZiM2ZhMTQt..."`                             |
| `UNITY_EDITOR_PATH`                 | All        | Path to Unity Editor installation                                              | `"/Applications/Unity/Hub/Editor/6000.3.10f1"`        |
| `UNITY_PROJECT_PATH`                | All        | Path to your Unity project root                                                | `"/Users/you/UnityProjects/MyGame"`                   |
| `BUILD_OUTPUT_PATH`                 | macOS, iOS | Path to the build output directory                                             | `"/Users/you/UnityProjects/MyGame/Build"`             |
| `BUILD_NAME`                        | macOS, iOS | Build product name (used to find the `_BackUpThisFolder` directory)            | `"MyGame"`                                            |
| `IOS_BUILD_PRODUCTS_PATH`           | iOS only   | Xcode build products directory containing `.dSYM` bundles                      | Refer to the script comments for a full example path. |

> **Note:**
>
> For Android, you don't need to specify `BUILD_OUTPUT_PATH`, `BUILD_NAME`, or `IOS_BUILD_PRODUCTS_PATH`. The script derives all paths from `UNITY_PROJECT_PATH`.

3. Run the script locally to verify the configuration.

```bash
chmod +x usymtool.sh
./usymtool.sh
```

After you successfully run the script, the message `Auth token acquired successfully` is displayed, with `Failed: 0` reported in the upload summary.

### Configure usymtool.ps1 for the Windows host platform

Before you configure the upload script, make sure you have the following information:

* Your Unity Project ID, which you can find under **Settings** in the [Unity Dashboard](https://cloud.unity.com).
* The Authorization header that you copied in the [previous step](#create-a-service-account).

To configure `usymtool.ps1` for the Windows host platform, follow these steps:

1. Open the script.
2. Fill in the **USER CONFIGURATION** section with the following information.

> **Important:**
>
> Don't add `-projectId` to the script. The script uses `usymtool`'s pre-signed URL upload mode and doesn't have a `-projectId` flag. If you do add `-projectId`, the script switches to a different upload mode that requires Google Cloud Storage credentials and ignores your service account token.

| Variable                             | Platforms    | Description                                                                    | Example                                           |
| ------------------------------------ | ------------ | ------------------------------------------------------------------------------ | ------------------------------------------------- |
| `$PLATFORM`                          | All          | Target platform                                                                | `"windows"` or `"android"`                        |
| `$USE_IL2CPP`                        | All          | Whether the build uses IL2CPP                                                  | `$true`                                           |
| `$UNITY_PROJECT_ID`                  | All          | Your Unity Project ID, as found on the **Settings** tab in the Unity Dashboard | `"12345678-abcd-1234-5678-12345678abcd"`          |
| `$UNITY_SERVICE_ACCOUNT_AUTH_HEADER` | All          | Authorization header copied in the [previous step](#create-a-service-account)  | `"Basic MmZiM2ZhMTQt..."`                         |
| `$UNITY_EDITOR_PATH`                 | All          | Path to Unity Editor installation                                              | `"C:\Program Files\Unity\Hub\Editor\6000.3.10f1"` |
| `$UNITY_PROJECT_PATH`                | All          | Path to your Unity project root                                                | `"C:\Users\you\UnityProjects\MyGame"`             |
| `$BUILD_OUTPUT_PATH`                 | Windows only | Path to the build output directory                                             | `"C:\Users\you\UnityProjects\MyGame\Build"`       |
| `$BUILD_NAME`                        | Windows only | Build product name, which is used to find the `_BackUpThisFolder` directory    | `"MyGame"`                                        |

> **Note:**
>
> For Android, you don't need to specify `$BUILD_OUTPUT_PATH` or `$BUILD_NAME`. The script derives all paths from `$UNITY_PROJECT_PATH`.

3. Run the script locally to verify your settings.

```powershell
.\usymtool.ps1
```

After you successfully run the script, the message `Auth token acquired successfully` is displayed, with `Failed: 0` reported in the upload summary.

### Override derived paths

If your project layout differs from the default platform-specific paths, you can override any derived path without modifying the platform logic. To override the default configuration, set the corresponding `_OVERRIDE` variable in the **ADVANCED** section of the script.

You might need to use an override if you use one of the following:

* [Mac computer with an Intel x86\_64 processor](#mac-computer-with-an-intel-x86_64-processor)
* [Unity 6 with the Bee build system](#unity-6-with-the-bee-build-system)

For additional override and troubleshooting information, refer to [Troubleshooting symbol file uploads from CI/CD pipelines](/cloud/developer-data/upload-symbol-files-ci-troubleshooting.md).

### Mac computer with an Intel x86\_64 processor

Although all Unity versions include binaries for both Intel and Apple Silicon processors, the `usymtool` script defaults to the paths for Apple Silicon processors. If you use a Mac computer with an Intel x86\_64 processor, then you need to set an override to ensure that the script runs the correct binary.

Starting with Unity 6.3, macOS tools moved from `Contents/Tools` to `Contents/Helpers`. Depending on your Unity version, add the corresponding line to set `USYMTOOL_PATH_OVERRIDE` to the Intel binary:

```bash title="Unity 6.3 and later"
USYMTOOL_PATH_OVERRIDE="${UNITY_EDITOR_PATH}/Unity.app/Contents/Helpers/usymtool"
```

```bash title="Unity 6.2 and earlier"
USYMTOOL_PATH_OVERRIDE="${UNITY_EDITOR_PATH}/Unity.app/Contents/Tools/macosx/usymtool"
```

### Unity 6 with the Bee build system

If you use Unity 6 with the Bee build system, then the default `il2cppFileRoot` folder might not match the relative paths embedded in your symbol files.

To override the default path and set it to the current directory, add the following line to the script's **ADVANCED** section:

```bash
IL2CPP_FILE_ROOT_OVERRIDE="."
```

> **Tip:**
>
> The exact paths and flags might vary depending on your Unity version. To find the correct invocation for your setup, perform a build from the Unity Editor with symbol upload enabled, and inspect the log file. The log file records the full `usymtool` command line and all resolved paths:
>
> * macOS: `~/Library/Logs/Unity/symbol_upload.log`
> * Windows: `%LOCALAPPDATA%\Unity\Editor\symbol_upload.log`

## Integrate with your CI pipeline

After you verify that the script works locally, follow these steps to add the script to your CI pipeline:

1. Commit the script to a `scripts/` directory in your repository.
2. Set the following variables in your CI platform:

* `PLATFORM`: The target platform. For example, `macos`, `ios`, `android`, or `windows`.
* `UNITY_EDITOR_PATH`: The path to the Unity Editor on the runner. For example, `/Applications/Unity/Hub/Editor/6000.3.10f1`.
* `BUILD_OUTPUT_PATH`: The path to the build output directory. For example, `$GITHUB_WORKSPACE/Build`.
* `BUILD_NAME`: Your build product name. For example, `MyGame`.

3. Store the following values in your platform's secrets manager, such as GitHub Secrets or GitLab CI Variables with masking enabled:

* `UNITY_SA_AUTH_HEADER`: The authorization header. For example, `Basic MmZiM2Zh...`.
* `UNITY_PROJECT_ID`: Your Unity project ID. For example, `12345678-abcd-1234-5678-12345678abcd`.

4. To ensure that no values are hardcoded, inject all configuration from CI variables at runtime.

After you add the script with all CI variables, the pipeline is fully automated.

For sample runner code that you can use for various host and target platforms, refer to [Runner examples for uploading debugging symbols from CI/CD pipelines](/cloud/developer-data/upload-symbol-files-runners.md).

## Verify your upload

The **Diagnostics** > **Debugging Symbols** page in the Dashboard shows only symbols uploaded through the Dashboard UI. Any symbols that you upload through `usymtool` don't appear on this page.

To verify that your CI upload is successful, follow these steps:

1. Check the `usymtool` output for the following messages at the end of a successful run:

   ```text
   time="<timestamp>" level=info msg="<uuid> successfully uploaded to cloud storage"
   time="<timestamp>" level=info msg="All <n> uploads completed with out error."
   time="<timestamp>" level=info msg="Usymtool run completed in <duration>."
   ```

> **Note:**
>
> If the output contains `level=warning` lines about missing symbol sections or DWARF data, then refer to [Troubleshooting](/cloud/developer-data/upload-symbol-files-ci-troubleshooting.md).

2. Trigger a crash in a build that matches the uploaded symbols.
3. Open the crash report in **Diagnostics**.
4. Confirm that the stack trace in the crash report shows the following instead of raw memory addresses:

* Function names
* File names
* Line numbers

If all information appears as expected, then the upload process is complete.
