# iOS > https://docs.errora.org/en/platforms/apple-ios Errora works with the official [Sentry Cocoa SDK](https://docs.sentry.io/platforms/apple/guides/ios/) unchanged. The SDK captures crashes on-device, reports app hangs and watchdog terminations, and `sentry-cli` uploads the dSYMs Errora needs to turn crash addresses into function names, files and lines. Create the project with the **iOS** platform so the UI shows the right snippets. ## Install **Swift Package Manager** — in Xcode, *File → Add Package Dependencies…*, then: ```text https://github.com/getsentry/sentry-cocoa ``` **CocoaPods:** ```ruby # Podfile pod 'Sentry' ``` ## Initialize Start the SDK as early as possible — in `application(_:didFinishLaunchingWithOptions:)`, or the `init()` of your SwiftUI `App`: ```swift import Sentry SentrySDK.start { options in options.dsn = "https://@/" options.environment = "production" options.tracesSampleRate = 0.2 // tracing options.configureProfiling = { // profiling $0.sessionSampleRate = 1.0 $0.lifecycle = .trace } options.attachScreenshot = true // screenshot on error options.attachViewHierarchy = true // view hierarchy on error options.sessionReplay.onErrorSampleRate = 1.0 options.sessionReplay.sessionSampleRate = 0.1 options.enableAppHangTracking = true // default: on options.appHangTimeoutInterval = 2 // seconds } ``` Older SDK versions configure profiling with `options.profilesSampleRate = 1.0` instead of `configureProfiling`; Errora accepts what either sends. ## Options worth enabling | Option | What you get in Errora | | --- | --- | | `tracesSampleRate` | [Performance](/en/products/performance): app start, UIViewController, network spans | | `configureProfiling` / `profilesSampleRate` | [Profiling](/en/products/profiling), symbolicated with your dSYMs | | `attachScreenshot` | A screenshot stored with each error, previewed on the issue page | | `attachViewHierarchy` | The view tree at the moment of the error, rendered as a tree on the issue page | | `sessionReplay.*SampleRate` | [Mobile session replay](/en/products/session-replay#mobile-replays) | | `enableAppHangTracking` | App hangs arrive as ordinary errors and group/alert like any issue | | `enableAutoSessionTracking` | Sessions for [release health](/en/products/release-health) — on by default | You don't need to set a release: the SDK uses `@+` automatically, and that is the string release health keys on. Screenshots, view hierarchies and Apple crash reports are [attachments](/en/products/issues#attachments): stored with their event, kept for the organization's [data retention](/en/account/retention), and dropped with the event when it is sampled out or spike-limited. ## Upload dSYMs A crash report holds instruction addresses. Errora symbolicates them **before grouping** with the dSYM whose debug id (Mach-O UUID) matches each loaded image — see [Debug files](/en/products/debug-files). ### 1. Produce dSYMs In the target's **Build Settings**, set **Debug Information Format** to **DWARF with dSYM File** — at least for the Release configuration. ### 2. Configure sentry-cli Install `sentry-cli` (`brew install getsentry/tools/sentry-cli`) and give it Errora's address. Either environment variables: ```bash export SENTRY_URL=https:// export SENTRY_AUTH_TOKEN=errora_pat_… export SENTRY_ORG= export SENTRY_PROJECT= ``` …or a `.sentryclirc` next to the project (keep the token out of git): ```ini [defaults] url = https:// org = project = [auth] token = errora_pat_… ``` The token is an Errora [personal access token](/en/account/tokens) whose owner is a **member** (or higher) of the organization. The organization slug is the one in your dashboard URL (`/organizations//…`). ### 3. Add an Xcode build phase **Build Phases → + → New Run Script Phase**, placed after *Compile Sources*: ```bash if [[ "$(uname -m)" == arm64 ]]; then export PATH="/opt/homebrew/bin:$PATH" fi if which sentry-cli >/dev/null; then ERROR=$(sentry-cli debug-files upload "$DWARF_DSYM_FOLDER_PATH" 2>&1 >/dev/null) if [ ! $? -eq 0 ]; then echo "warning: sentry-cli - $ERROR" fi else echo "warning: sentry-cli not installed" fi ``` Add this to the phase's **Input Files** so Xcode runs it after the dSYM exists (and so it works with user script sandboxing): ```text ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME} ``` ### Or with fastlane ```ruby lane :upload_symbols do sentry_debug_files_upload( url: "https://", auth_token: ENV["SENTRY_AUTH_TOKEN"], org_slug: "", project_slug: "", ) end ``` Run it after `build_app` (or `gym`), so the build's dSYMs are on disk. You can also upload a debug file by hand from the browser, under **Settings → Debug files**. ## Verify Build a **Release** configuration, run the app **without** the debugger attached (the debugger swallows crashes), then: ```swift SentrySDK.capture(error: NSError(domain: "errora.smoke-test", code: 1)) // or crash for real: SentrySDK.crash() ``` A crash is sent the next time the app launches. Open the issue: frames should show function names, files and lines, with inlined frames expanded. If a frame isn't symbolicated, the issue page lists the missing debug id and the image it belongs to. ## Troubleshooting | Symptom | Cause / fix | | --- | --- | | Frames show only addresses | The dSYM for that build wasn't uploaded — check the build log and **Debug files** | | Swift symbols look like `$s7MyApp…` | The Errora image demangles Swift with the bundled Swift runtime; a custom image needs `libswiftCore.so` — see [Debug files](/en/products/debug-files#limitations) | | No crash after `SentrySDK.crash()` | The debugger was attached, or the app wasn't relaunched | | Upload fails with `401` | Wrong or revoked token, or `SENTRY_URL` isn't set (sentry-cli defaults to sentry.io) | | No release health data | `enableAutoSessionTracking` was turned off |