---
title: "Size Analysis"
description: "Upload iOS builds to Sentry for size analysis."
url: https://docs.sentry.io/platforms/apple/guides/ios/size-analysis/
---

# Size Analysis | Sentry for iOS

[Size Analysis](https://docs.sentry.io/product/size-analysis.md) helps monitor your mobile app's size in pre-production to prevent unexpected size increases (regressions) from reaching users. Aside from being courteous to your users, a smaller app size helps boost installation and retention rates, especially for customers with limited storage or slower connections.

## [Getting Started](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#getting-started)

Size Analysis is most effective when part of your CI pipeline. To set up, follow our guide on [integrating into CI](https://docs.sentry.io/product/size-analysis/integrating-into-ci.md).

**Accepted Formats**: XCArchive (preferred) | IPA

**Upload Mechanisms**: [Fastlane Plugin](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#uploading-with-fastlane) *or* [Sentry CLI](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#uploading-with-the-sentry-cli)

### [Uploading With Fastlane](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#uploading-with-fastlane)

The Fastlane plugin can be used to upload XCArchive or IPA builds to Sentry. On GitHub Actions, Fastlane will automatically detect your [build's metadata](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#upload-metadata) and include it in the upload. In other Continuous Integration (CI) environments, you may need to manually set metadata values.

Uploading IPA files requires Sentry Fastlane plugin version `2.0.0-rc.3` or later. XCArchive uploads are supported in earlier versions.

1. Configure the [Sentry Fastlane plugin](https://docs.sentry.io/platforms/apple/guides/ios/dsym.md#sentry-fastlane-plugin) (version `2.5.1`):

   ```ruby
   bundle exec fastlane add_plugin fastlane-plugin-sentry
   ```

2. Set up `SENTRY_AUTH_TOKEN` in your environment (you can generate a token [here](https://sentry.sentry.io/settings/auth-tokens/))

3. In `FastFile`, add a call to `sentry_upload_build` after your build step.

   **Uploading an XCArchive (preferred):**

   When using `build_ios_app`, the XCArchive path is automatically detected from `SharedValues::XCODEBUILD_ARCHIVE`:

   `Fastfile`

   ```ruby
   lane :upload_to_sentry do
     build_ios_app(
       scheme: 'YourScheme',
       configuration: 'Release'
     )
     sentry_upload_build(
       org_slug: 'your-org',
       project_slug: 'your-project',
       build_configuration: 'Release'
     )
   end
   ```

   You can also explicitly specify the `xcarchive_path`:

   `Fastfile`

   ```ruby
   lane :upload_to_sentry do
     sentry_upload_build(
       org_slug: 'your-org',
       project_slug: 'your-project',
       xcarchive_path: 'path/to/YourApp.xcarchive',
       build_configuration: 'Release'
     )
   end
   ```

   **Uploading an IPA:**

   When using `build_ios_app`, the IPA path is automatically detected from `SharedValues::IPA_OUTPUT_PATH`.

   `Fastfile`

   ```ruby
   lane :upload_to_sentry do
     build_ios_app(
       scheme: 'YourScheme',
       configuration: 'Release'
     )
     sentry_upload_build(
       org_slug: 'your-org',
       project_slug: 'your-project',
       build_configuration: 'Release'
     )
   end
   ```

   To upload an IPA instead of the XCArchive, explicitly specify `ipa_path`:

   `Fastfile`

   ```ruby
   lane :upload_to_sentry do
     build_ios_app(
       scheme: 'YourScheme',
       configuration: 'Release'
     )
     sentry_upload_build(
       org_slug: 'your-org',
       project_slug: 'your-project',
       ipa_path: 'path/to/YourApp.ipa',
       build_configuration: 'Release'
     )
   end
   ```

4. After an upload has successfully processed, confirm the metadata is correct in the Sentry UI

The Fastlane plugin automatically detects the following build metadata. If needed, the metadata values can be overridden by passing parameters to `sentry_upload_build`:

`Fastfile`

```ruby
sentry_upload_build(
  org_slug: 'your-org',
  project_slug: 'your-project',
  xcarchive_path: 'path/to/YourApp.xcarchive', # or ipa_path: 'path/to/YourApp.ipa'
  build_configuration: 'Release',
  # Optional metadata overrides:
  head_sha: 'abc123',
  base_sha: 'def456',
  vcs_provider: 'github',
  head_repo_name: 'organization/repository',
  base_repo_name: 'organization/repository',
  head_ref: 'feature-branch',
  base_ref: 'main',
  pr_number: '42'
)
```

See the [Fastlane repo](https://github.com/getsentry/sentry-fastlane-plugin) for more information.

### [Uploading with the Sentry CLI](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#uploading-with-the-sentry-cli)

1. Install the [sentry-cli](https://docs.sentry.io/cli.md) (version `3.3.5`)

   We recommend using the latest version for the best possible experience, but at a minimum version `2.58.2` is required.

2. Authenticate the Sentry CLI by [following these steps](https://docs.sentry.io/cli/configuration.md#to-authenticate-manually)

3. Build your app to create an XCArchive (preferred) or IPA

4. Invoke the following CLI command to trigger the upload:

   ```bash
   sentry-cli build upload app.xcarchive \
     --org your-org \
     --project your-project \
     --build-configuration Release
   ```

5. After an upload has successfully processed, confirm the metadata is correct in the Sentry UI

## [Upload Metadata](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#upload-metadata)

We use build metadata to organize builds in the UI and ensure correct comparisons.

| Field                   | Description                                                                                                                                                                                                                                              |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `org`\*                 | Sentry organization slug                                                                                                                                                                                                                                 |
| `project`\*             | Sentry project slug                                                                                                                                                                                                                                      |
| `build-configuration`\* | Build configuration describing how the app was built, for example `Release` or `Debug` or `Release-Bazel`                                                                                                                                                |
| `head-sha`              | Current commit SHA                                                                                                                                                                                                                                       |
| `base-sha`              | Base commit SHA (for comparisons, recommended to use the branch's merge-base)                                                                                                                                                                            |
| `vcs-provider`          | VCS provider name (for example `github`, `gitlab`, `bitbucket`, `azure`, `github_enterprise`). If not provided, the provider will be auto-detected from the git remote URL. Note: Only `github` and `github_enterprise` are supported for status checks. |
| `head-repo-name`        | Repository name (`org/repo`)                                                                                                                                                                                                                             |
| `pr-number`             | Pull request number                                                                                                                                                                                                                                      |
| `head-ref`              | Branch or tag name                                                                                                                                                                                                                                       |
| `base-ref`              | Base branch name                                                                                                                                                                                                                                         |
| `install-group`         | [Install group(s)](https://docs.sentry.io/product/build-distribution.md#install-groups) to control update visibility between builds. Can be specified multiple times                                                                                     |

\* *required field*

### [Build Configuration](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#build-configuration)

Features such as automatically comparing the head build against the base build **will only compare builds of the same build configuration**. This is important to consider when setting up Size Analysis in your CI. For example, `Release` and `Debug` builds can be drastically different depending on the compiler and linker settings used during the build process. Trying to compare the two would give unexpected results.

## [Understanding App Size](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#understanding-app-size)

### [Download vs. Install Size](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#download-vs-install-size)

Sentry's iOS app size metric tracks the unencrypted install size of your app on the latest iPhone hardware running the latest iOS version. Since install size is what users see before downloading your app and before deciding if an app should be deleted, it's the most important metric to track and reduce on iOS.

Apps are compressed before they are downloaded, so the actual number of bytes transferred will be lower than the amount of storage taken up by an installed app. Users can see both these numbers, but install size is more prominently displayed.

The install size is what you see when viewing the details for an app on the App Store:

By default, download size will only be displayed if an app is over the Apple determined limit of 200 MB and the user is not on Wi-Fi. Hidden in the iOS Settings app, users can configure the App Store to always warn them of the download size of an app before starting the download, still only when not connected to Wi-Fi.

Users can also review the app's install size in the Settings app.

It's important to reduce install size, because this is what many users see when deciding if an app should be downloaded or what apps to delete.

**Regarding App Clips**: By default, Sentry measures all content inside the uploaded xcarchives (minus app thinning), which means that if App Clips are included, we will measure and add their impact to the app size. We do this so users can monitor changes to the App Clips on each version, but physical devices do not download App Clips with the apps, so the install and download sizes will be bigger than the ones displayed in TestFlight or the App Store.

### [App Thinning](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#app-thinning)

App Thinning is Apple's technology that automatically optimizes the delivery of iOS apps to reduce their download size for end users. When your app is uploaded to the App Store, Apple creates device-specific variants that only include the resources needed for each device type. For example, an iPhone SE doesn't need images intended for iPads.

Sentry Size Analysis **does not perform any app thinning** as part of the analysis, the underlying app is untouched and results shown as-is.

If you want results targeting a specific device type (recommended), apply app thinning **before** uploading to Sentry. This can be configured via Export Options when building the app. First create an `export_options.plist` file with the desired device type:

`export_options.plist`

```xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>ad-hoc</string>
<key>team_id</key>
<string>your-team-id</string> <!-- set to your ID -->
<key>thinning</key>
<string>iPhone17,1</string> <!-- set to your device type -->
</dict>
</plist>
```

And then pass this file to `xcodebuild` via the `-exportOptionsPlist export_options.plist` flag when building the app. This will produce a `app-thinning.plist` file in your build directory with information on the created app variants and where they are located on disk. Pick the appropriate IPA when uploading to Sentry.

If a build is uploaded without first being thinned, you may see multiple copies of your images (ex. different idiom and colorspace values) in your build analysis. We recommend uploading the thinned build to Sentry for the best results.

### [WatchOS Architectures](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#watchos-architectures)

WatchOS apps produced by Xcode often contain both `arm64_32` and `arm64` architectures in a single fat binary. By default Sentry calculates the size of this data as-is, however, your end users will only download whatever architecture is necessary for their device. It's recommended to apply [App Thinning](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#app-thinning) before uploading for more representative results.

### [Code Signature](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#code-signature)

App bundles contain code signature data within `_CodeSignature/` directories. In these you'll find a `CodeResources` plist file with hashes of every file within the bundle. Similarly, Mach-O binaries contain additional hashes of every page block within its `LC_CODE_SIGNATURE` load command. This means the size of code signature data will scale linearly with the amount of files in your bundle and size of your binaries.

By default Sentry calculates the size of this data as-is. You may notice differences when comparing against your app downloaded from the App Store. For example, Xcode 26 archives only codesign with `SHA256` hashes, but the App Store can use both `SHA1` and `SHA256` hashes. In other words, App Store downloads of your app may be slightly larger than what's produced by Xcode. This App Store behavior is subject to change at any time.

If you'd like to compare the impact of this on your app, you can re-sign your app before uploading to Sentry:

```bash
# Inspect the current code signature
codesign -dvvv '/path/to/your/app.app'

# Re-sign with a new code signature
codesign --force \
  --sign 'Apple Distribution: Your Team (team_id)' \
  --digest-algorithm sha1 \
  --digest-algorithm sha256 \
  '/path/to/your/app.app'
```

This will force both `SHA1` and `SHA256` hashes to be used.

### [App Store Connect File Sizes](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#app-store-connect-file-sizes)

App Store Connect has a feature for `App File Sizes` which provides a report of your app size thinned for various device types. While we strive to be consistent with these numbers, you may see differences between the reported Sentry size and the Apple size. It's important to note that the reported Apple sizes are not consistent with the rest of their tooling, such as the Size Report generated by Xcode, and these are all estimated sizes. You can [learn more about these differences here](https://github.com/EmergeTools/app-store-size-example) for additional information.

## [Uploading Best Practices](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#uploading-best-practices)

### [Strip Swift AST](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#strip-swift-ast)

For optimal processing speeds, strip `__swift_ast` from your dSYMs before uploading to Sentry. This section of the binary is a copy of your code's swiftmodule file and is only used for runtime debugging with LLDB. It is not required for symbolication, Size Analysis, or Build Distribution.

The script below can be used to strip `__swift_ast` from your dSYMs. The xcarchive is modified in-place. Back up first if needed.

**Prerequisites**: Xcode command line tools (otool, lipo), Python 3

```bash
#!/bin/bash
set -euo pipefail

if [[ $# -ne 1 ]]; then
  echo "Usage: $0 <path-to-xcarchive>" >&2
  exit 1
fi

XCARCHIVE="$1"
DSYMS_DIR="$XCARCHIVE/dSYMs"

if [[ ! -d "$DSYMS_DIR" ]]; then
  echo "Error: No dSYMs directory found at $DSYMS_DIR" >&2
  exit 1
fi

TOTAL_ZEROED=0
STRIPPED_COUNT=0

# Zero out __swift_ast in a single-arch Mach-O binary.
# Prints the number of bytes zeroed (0 if section not found).
strip_thin_binary() {
  local binary="$1"

  local ast_info
  ast_info=$(xcrun otool -l "$binary" 2>/dev/null | awk '
    /sectname __swift_ast/ { found = 1 }
    found && /^[[:space:]]+size / {
      cmd = "printf \"%d\" " $2
      cmd | getline dec_size
      close(cmd)
    }
    found && /^[[:space:]]+offset / {
      print dec_size " " $2
      found = 0
    }
  ')

  if [[ -z "$ast_info" ]]; then
    echo "0"
    return
  fi

  local ast_size ast_offset
  ast_size=$(echo "$ast_info" | awk '{print $1}')
  ast_offset=$(echo "$ast_info" | awk '{print $2}')

  if [[ "$ast_size" -eq 0 ]]; then
    echo "0"
    return
  fi

  # Skip if already zeroed
  local already_zeroed
  already_zeroed=$(/usr/bin/python3 -c "
import sys
with open(sys.argv[1], 'rb') as f:
    f.seek(int(sys.argv[2]))
    print('1' if f.read(int(sys.argv[3])) == b'\0' * int(sys.argv[3]) else '0')
" "$binary" "$ast_offset" "$ast_size")

  if [[ "$already_zeroed" == "1" ]]; then
    echo "0"
    return
  fi

  chmod u+w "$binary" 2>/dev/null || true
  /usr/bin/python3 -c "
import sys
with open(sys.argv[1], 'r+b') as f:
    f.seek(int(sys.argv[2]))
    f.write(b'\0' * int(sys.argv[3]))
" "$binary" "$ast_offset" "$ast_size"

  echo "$ast_size"
}

# Handle both fat (multi-arch) and thin (single-arch) binaries.
strip_binary() {
  local binary="$1"

  local lipo_info
  lipo_info=$(xcrun lipo -info "$binary" 2>/dev/null) || true

  if echo "$lipo_info" | grep -q "Architectures in the fat file"; then
    local archs
    archs=$(echo "$lipo_info" | sed 's/.*: //')

    local tmp_dir
    tmp_dir=$(mktemp -d)
    local thin_files=()
    local saved=0

    for arch in $archs; do
      local thin_file="$tmp_dir/$arch"
      xcrun lipo "$binary" -thin "$arch" -output "$thin_file"

      local bytes_str
      bytes_str=$(strip_thin_binary "$thin_file")
      saved=$((saved + bytes_str))

      thin_files+=("$thin_file")
    done

    if [[ $saved -gt 0 ]]; then
      chmod u+w "$binary" 2>/dev/null || true
      xcrun lipo -create "${thin_files[@]}" -output "$binary"
    fi

    rm -rf "$tmp_dir"
    echo "$saved"
  else
    strip_thin_binary "$binary"
  fi
}

echo "Zeroing __swift_ast in dSYMs in: $DSYMS_DIR"
echo ""

while IFS= read -r dsym_bundle; do
  dsym_name=$(basename "$dsym_bundle")
  dwarf_dir="$dsym_bundle/Contents/Resources/DWARF"

  if [[ ! -d "$dwarf_dir" ]]; then
    continue
  fi

  for binary in "$dwarf_dir"/*; do
    [[ -f "$binary" ]] || continue

    zeroed=$(strip_binary "$binary")
    if [[ "$zeroed" -gt 0 ]]; then
      zeroed_mb=$(echo "scale=1; $zeroed / 1048576" | bc)
      echo "  $dsym_name — zeroed ${zeroed_mb} MB"
      TOTAL_ZEROED=$((TOTAL_ZEROED + zeroed))
      STRIPPED_COUNT=$((STRIPPED_COUNT + 1))
    fi
  done
done < <(find "$DSYMS_DIR" -name "*.dSYM" -type d)

TOTAL_MB=$(echo "scale=1; $TOTAL_ZEROED / 1000000" | bc)
echo ""
echo "Done. Processed $STRIPPED_COUNT dSYM(s), zeroed ${TOTAL_MB} MB of __swift_ast data."
```

## [What's Next?](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis.md#whats-next)

We strongly recommend integrating Size Analysis into your CI pipeline. Follow our guide on [getting set up in CI](https://docs.sentry.io/product/size-analysis/integrating-into-ci.md).

* #### [Insights](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis/insights.md)

  See how Size Analysis surfaces trends for your iOS builds.

## Pages in this section

- [Insights](https://docs.sentry.io/platforms/apple/guides/ios/size-analysis/insights.md)
