iOS Swift Setup Guide • 13 min read

iOS Crash Reporting: Complete Setup Guide for Swift Apps (2026)

Xcode Organizer is not enough for production iOS apps. This step-by-step guide shows you how to add real-time crash reporting to your Swift app using Logtrics — including dSYM symbolication, non-fatal error capture, user context, and CI automation.

Logtrics
Logtrics Team

1. Why Xcode Organizer Is Not Enough

Every iOS developer knows Xcode Organizer's Crashes section. It seems like the obvious place to look for production crashes. But Xcode Organizer has fundamental limitations that make it unsuitable as your sole crash reporting solution.

Only opt-in users are included

Xcode Organizer only receives crash reports from users who have opted in to sharing diagnostics with developers. Studies suggest fewer than 30% of iOS users have this enabled. This means you are seeing a fraction of your actual crashes, and the subset may not be representative of your user base.

Hours of delay

Crashes appear in Xcode Organizer with a multi-hour delay — often 6 to 12 hours after they occur. For a high-volume production app, this means a critical crash can affect thousands of users before you even know it exists. Real-time crash reporting with Logtrics sends you an alert within seconds of the first occurrence.

No pre-crash log context

Xcode Organizer shows only the crash stack trace. It has no concept of what the user was doing, what API calls were made, or what state the app was in. Without this context, determining root cause requires guesswork and hours of code review.

No custom error capture

You cannot record non-fatal errors, custom events, or structured context in Xcode Organizer. If a payment fails, a data migration throws, or a critical feature path encounters an unexpected condition — none of that is visible unless it results in a hard crash.

No alerting

There is no way to receive a Slack or email notification when a new crash occurs. You must manually open Xcode Organizer, check the Crashes tab, and notice the new issue yourself.

2. Installing the Logtrics iOS SDK via Swift Package Manager

The Logtrics iOS SDK is distributed via Swift Package Manager. No CocoaPods or Carthage configuration is required.

Option A: Xcode UI

  1. 1 Open your project in Xcode
  2. 2 Go to File → Add Package Dependencies
  3. 3 Enter the Logtrics package URL in the search bar
  4. 4 Select your target and click Add Package

// Package URL

https://github.com/logtrics/logtrics-ios-sdk

Option B: Package.swift

// Package.swift

dependencies: [

  .package(

    url: "https://github.com/logtrics/logtrics-ios-sdk",

    from: "2.0.0"

  )

],

targets: [

  .target(

    name: "YourApp",

    dependencies: ["Logtrics"]

  )

]

3. Initializing Logtrics in AppDelegate or SwiftUI App

Initialize Logtrics as early as possible in your app's lifecycle. For UIKit apps, this is in AppDelegate.application(_:didFinishLaunchingWithOptions:). For SwiftUI apps, it is in your @main App struct init.

UIKit — AppDelegate.swift

import

UIKit


import

Logtrics



@main

class AppDelegate: UIResponder, UIApplicationDelegate {


  func application(

    _ application: UIApplication,

    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?

  ) -> Bool {


    // Initialize Logtrics — first line in didFinishLaunching

    Logtrics.configure(apiKey: "YOUR_API_KEY")


    return true

  }

}

SwiftUI — MyApp.swift

import

SwiftUI


import

Logtrics



@main

struct MyApp: App {


  init() {

    // Initialize before any views render

    Logtrics.configure(apiKey: "YOUR_API_KEY")

  }


  var body: some Scene {

    WindowGroup {

      ContentView()

    }

  }

}

Security note: Never commit your API key directly to source control. Use Xcode build settings (Info.plist with a build setting reference), a secrets manager, or environment variables passed at build time in CI. Retrieve it at runtime with Bundle.main.object(forInfoDictionaryKey: "LOGTRICS_API_KEY") as? String.

4. dSYM Files: What They Are and How to Upload Them

A dSYM (debug symbol file) is the key to readable iOS crash reports. When Xcode builds your app for release, it compiles Swift to machine code and strips the debug information from the binary to reduce size. The debug information — including your file names, function names, and line numbers — is stored separately in a .dSYM bundle.

Enabling dSYM generation

Ensure your Release build configuration generates dSYMs. In Xcode Build Settings, search for "Debug Information Format" and set the Release configuration to "DWARF with dSYM File".

// Xcode Build Setting

DEBUG_INFORMATION_FORMAT = dwarf-with-dsym

Manual upload via Xcode Build Phase

Add a Run Script phase to your target that fires after each archive build. This automatically uploads the dSYM every time you create an archive for TestFlight or App Store distribution.

In Xcode, go to your target → Build Phases → + → New Run Script Phase. Add it after the "Copy Bundle Resources" step:

#!/bin/bash

# Upload dSYM to Logtrics after archive


if [ "${CONFIGURATION}" == "Release" ]; then

  logtrics-cli upload-dsym \

    --api-key "${LOGTRICS_API_KEY}" \

    --bundle-id "${PRODUCT_BUNDLE_IDENTIFIER}" \

    --version "${MARKETING_VERSION}" \

    --build "${CURRENT_PROJECT_VERSION}" \

    --path "${DWARF_DSYM_FOLDER_PATH}"

fi

5. Automating dSYM Upload in CI

For teams using CI/CD pipelines (GitHub Actions, Bitrise, CircleCI, Fastlane), automating dSYM upload ensures no release ever ships without symbolication configured.

GitHub Actions Example

# .github/workflows/release.yml

- name: Upload dSYMs to Logtrics

  env:

    LOGTRICS_API_KEY: ${{ secrets.LOGTRICS_API_KEY }}

  run: |

    logtrics-cli upload-dsym \

      --api-key "$LOGTRICS_API_KEY" \

      --path ./build/MyApp.xcarchive/dSYMs

Fastlane Lane

# Fastfile

lane :upload_symbols do

  sh(

    "logtrics-cli upload-dsym",

    "--api-key #{ENV['LOGTRICS_API_KEY']}",

    "--path #{lane_context[SharedValues::DSYM_OUTPUT_PATH]}"

  )

end

Install the CLI: brew install logtrics-cli on macOS, or via the npm package npm install -g @logtrics/cli for CI environments.

6. Capturing Non-Fatal Errors

Fatal crashes are only part of the picture. Non-fatal errors — conditions your app recovers from gracefully but that indicate something went wrong — are equally important to track. Use Logtrics.recordError() to capture them.

Recording a non-fatal error

// Catching a network error without crashing

do {

  let userData = try await apiClient.fetchUser(id: userId)

  updateUI(with: userData)

} catch {

  // App recovers by showing a fallback UI

  showErrorState()


  // But we still want to know about this

  Logtrics.recordError(

    error,

    userInfo: [

      "userId": userId,

      "endpoint": "/api/user",

      "statusCode": (error as? APIError)?.statusCode ?? 0

    ]

  )

}

Common non-fatal error scenarios to track

  • API calls that return unexpected status codes (404, 500)
  • Core Data migrations that encounter unexpected schema
  • JSONDecoding failures for server-returned data
  • In-app purchases that fail at the transaction level
  • Push notification registration failures
  • Feature flags that cannot be fetched

7. Setting User Context

Attaching user identity to crashes lets you understand which users are affected, contact them proactively, and correlate crashes with specific account types or subscription tiers.

Setting the current user

// Call this after successful authentication

func didSignIn(user: User) {

  Logtrics.setUser(

    id: user.id,

    email: user.email, // optional

    name: user.displayName // optional

  )


  // Add custom attributes for additional context

  Logtrics.setUserAttribute("plan", value: user.subscriptionPlan)

  Logtrics.setUserAttribute("accountAge", value: user.daysSinceSignup)

}


// Clear on sign out

func didSignOut() {

  Logtrics.clearUser()

}

8. Screen Tracking

Tracking which screen the user was on when a crash occurred is invaluable context. Logtrics can auto-track screen names, or you can set them manually for more precise control.

Manual screen tracking in UIKit

class

CheckoutViewController: UIViewController {


  override func viewDidAppear(_ animated: Bool) {

    super.viewDidAppear(animated)

    Logtrics.trackScreen("Checkout")

  }

}

SwiftUI View tracking with onAppear

struct CheckoutView: View {

  var body: some View {

    VStack {

      // ... view content

    }

    .onAppear {

      Logtrics.trackScreen("Checkout")

    }

  }

}

9. Remote Logging in Swift

Remote logging is one of the most powerful features of Logtrics. Log statements added throughout your app are captured and stored alongside crash data, giving you the full context of what happened before a crash.

Logging levels and examples

// Debug — detailed tracing for development insight

Logtrics.log(.debug, "Loading product catalog: \(categoryId)")


// Info — significant user actions and state changes

Logtrics.log(.info, "User added item to cart: \(productId)")


// Warn — unexpected but recoverable situations

Logtrics.log(.warn, "Payment API slow: \(latencyMs)ms, threshold: 3000ms")


// Error — failures that impact functionality

Logtrics.log(.error, "Payment declined: \(declineCode)")

Tip: You do not need to log everything — focus on the key decision points and state transitions in your critical user flows: authentication, payments, onboarding, and core feature actions. These are the logs that will explain 90% of your crashes.

10. Configuring Real-Time Alerts

Once your SDK is integrated and crashes are being captured, configure alerts so your team is notified immediately when a new crash occurs in production.

Slack alerts

In the Logtrics dashboard, go to Settings → Integrations → Slack. Add your Slack webhook URL. Each new crash issue sends a message with the crash title, affected user count, device model, OS version, and a link to the crash details page.

Email alerts

Go to Settings → Alerts → Email. Add team member email addresses. Configure whether to alert on every new crash type, or only when a threshold is crossed (e.g., 10 occurrences in 5 minutes).

Webhook (PagerDuty, custom)

Go to Settings → Integrations → Webhooks. Add your endpoint URL. Logtrics sends a JSON payload with the crash details on each new crash. Use this to integrate with PagerDuty, Opsgenie, or a custom alerting system.

11. Best Practices

Initialize as early as possible

Place Logtrics.configure() as the very first line of your app delegate or App struct init. Any crash that occurs before initialization cannot be captured.

Upload dSYMs on every release build

If you skip a dSYM upload for a version that goes to production, every crash from that version will have unreadable stack traces. Automate it in CI to guarantee it never gets missed.

Use log levels consistently

Reserve .error for actual failures that affect functionality. Use .warn for things that are unexpected but handled. This makes it easy to quickly filter the log timeline when investigating a crash.

Set user context before the first meaningful action

Call Logtrics.setUser() immediately after authentication completes. This ensures every subsequent crash is tied to a specific user ID, making it possible to identify affected accounts and reach out proactively.

Track your critical user flows with screen names

Add screen tracking at least for your checkout, authentication, onboarding, and settings flows. Knowing which screen the user was on narrows down investigation scope enormously.

Do not log PII or sensitive data

Never log credit card numbers, passwords, full names, or government IDs. Log user IDs (internal, non-PII identifiers) and anonymized context instead. Follow your app's data retention and privacy policy.

FAQ

Why is Xcode Organizer not enough for production iOS crash reporting?

Xcode Organizer only shows crashes from users who have opted into sharing diagnostics with Apple, which is a fraction of your total user base. It has a multi-hour delay before crashes appear, provides no real-time alerts, shows no pre-crash log context, and does not support custom error capture or non-fatal error recording. For production apps, you need a dedicated crash reporter like Logtrics that captures all crashes in real time, supports custom context, and sends instant Slack or email alerts.

What is a dSYM file and why does it matter for iOS crash reporting?

A dSYM (debug symbol file) is generated by Xcode when you build your app in release configuration with debug symbols enabled. It maps the raw memory addresses in a crash report back to your original Swift source file names and line numbers. Without the dSYM, a crash stack trace shows raw hex addresses like 0x00001000a3f0 instead of MyViewController.swift:84. Every iOS crash reporter requires dSYM upload to make crash reports readable.

How do I automate dSYM upload to Logtrics in CI?

After building your app in CI (GitHub Actions, Bitrise, CircleCI, etc.), add a step that runs the Logtrics CLI dSYM upload command. The CLI takes your API key and the path to the .dSYM files generated by Xcode. The dSYMs are typically found in the build directory or exported as part of an .xcarchive. You can also use the Xcode build phase script approach to upload dSYMs automatically as part of every archive build.

What is the difference between a fatal crash and a non-fatal error in iOS?

A fatal crash terminates the app process — the user sees the app close unexpectedly. These are captured automatically by crash reporters. A non-fatal error is an unexpected condition your app handles gracefully (catches and recovers from) but that still indicates something went wrong — a failed network request, a failed data migration, an unexpected nil. Non-fatal errors must be captured manually using Logtrics.recordError(), and they are just as important to track because they indicate problems your users are hitting without you knowing.

Add iOS Crash Reporting in Minutes

Start with 10,000 events per month — free, no credit card required. One Swift Package Manager install, one line of initialization code, and your app is reporting crashes in real time with AI root cause analysis and Slack alerts.