DebugBundle
SDKs

Swift SDK

Install DebugBundle in UIKit and SwiftUI apps with URLSession trace injection, offline queueing, SwiftLog, crash replay, and remote probes.

The Swift SDK is the native Apple-platform client SDK for iOS and iPadOS applications. It captures handled exceptions, next-launch crash evidence, UIKit and SwiftUI lifecycle breadcrumbs, first-party network request failures, structured logs, and always-on diagnostic probes without throwing back into app code.

Swift is a mobile client SDK, not a browser relay host. It sends mobile events to the configured ingestion endpoint and uses explicit first-party URLSession or Alamofire instrumentation for trace correlation; browser relay settings such as transportMode, allowedOrigins, and CORS preflight handling belong to the Browser SDK plus a backend/server SDK relay.

The SDK is available as debugbundle-swift v0.1.0 through Swift Package Manager. The repository is live at https://github.com/debugbundle/debugbundle-swift.

Installation

Add the package to your app target:

// Package.swift
.dependencies: [
    .package(url: "https://github.com/debugbundle/debugbundle-swift", from: "0.1.0")
],
.targets: [
    .target(
        name: "CheckoutApp",
        dependencies: [
            .product(name: "DebugBundle", package: "debugbundle-swift"),
            .product(name: "DebugBundleURLSession", package: "debugbundle-swift"),
            .product(name: "DebugBundleUIKit", package: "debugbundle-swift"),
            .product(name: "DebugBundleSwiftUI", package: "debugbundle-swift"),
            .product(name: "DebugBundleSwiftLog", package: "debugbundle-swift")
        ]
    )
]

In Xcode, you can also use File -> Add Package Dependencies... with the repository URL https://github.com/debugbundle/debugbundle-swift and select version 0.1.0 or a compatible version range.

The package currently supports iOS 15+ and exposes focused products for core capture, URLSession, Alamofire, UIKit, SwiftUI, SwiftLog, crash reporting, and test support.

Initialize

SwiftUI

import DebugBundle
import DebugBundleSwiftUI

@main
struct CheckoutApp: App {
    init() {
        DebugBundle.initialize(
            DebugBundleConfig(
                projectToken: Bundle.main.debugBundleProjectToken,
                service: "checkout-ios",
                environment: "production",
                releaseChannel: "app-store"
            )
        )
    }

    var body: some Scene {
        WindowGroup {
            CheckoutRootView()
                .debugBundleScreen("CheckoutRoot")
        }
    }
}

UIKit

import DebugBundle
import DebugBundleUIKit
import UIKit

final class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
    ) -> Bool {
        DebugBundle.initialize(
            DebugBundleConfig(
                projectToken: Bundle.main.debugBundleProjectToken,
                service: "checkout-ios",
                environment: "production"
            )
        )

        DebugBundleUIKit.install(application: application)
        return true
    }
}

DebugBundle.initialize is fail-open. If the project token or endpoint is missing, the SDK degrades to a no-op capture path and reports that state through DebugBundle.status instead of crashing the host app or pretending capture is healthy.

Capture

import DebugBundle

DebugBundle.captureMessage("checkout_started")
DebugBundle.captureLog("payment retry", level: .warning, context: ["attempt": attempt])
DebugBundle.setContext("tenant", value: tenantID)

Task {
    do {
        try await DebugBundle.captureAsync(context: ["screen": "Checkout"]) {
            try await checkout()
        }
    } catch {
        DebugBundle.captureException(error, context: ["flow": "checkout"])
    }

    await DebugBundle.flush()
}

SDK capture calls are no-throw by default. captureAsync is the explicit wrapper when you want to capture an application error and rethrow it to your own calling code.

Network Capture

URLSession instrumentation is explicit and scoped to first-party targets:

import DebugBundleURLSession

let configuration = URLSessionConfiguration.default
configuration.debugBundleInstrumented(
    tracePropagationTargets: ["https://api.example.com"]
)

let session = URLSession(configuration: configuration)

If you want a small wrapper around request execution and request_event recording, use the instrumented session helper:

import DebugBundleURLSession

let instrumentedSession = DebugBundleInstrumentedURLSession(
    session: .shared,
    tracePropagationTargets: [.host("api.example.com")]
)

Alamofire support uses the same target model:

import Alamofire
import DebugBundleAlamofire

let session = Session.debugBundleInstrumented(
    tracePropagationTargets: ["https://api.example.com"]
)

Matching requests receive X-DebugBundle-Trace-Id, network breadcrumbs, and policy-driven request_event promotion for failed responses. The SDK captures allowlisted headers only and leaves request and response bodies disabled by default.

Screens And Logs

SwiftUI helpers record screen and action breadcrumbs without introspecting view state:

CheckoutView()
    .debugBundleScreen("Checkout")
    .debugBundleAction("tap", targetType: "button", resourceName: "place-order")

UIKit helpers support explicit screen naming from view controllers:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    DebugBundleUIKit.recordViewControllerAppear(self, screenName: "Checkout", animated: animated)
}

SwiftLog support is additive and preserves existing logger output:

import DebugBundleSwiftLog
import Logging

LoggingSystem.bootstrap { label in
    DebugBundleLogHandler(label: label)
}

Offline Queue And Crash Replay

The Swift runtime writes a bounded file-backed offline queue under app-private Application Support storage by default. Queue limits are controlled by offlineQueueMaxEvents, offlineQueueMaxBytes, and offlineQueueTtl, and queue files use an explicit file protection class.

DebugBundleCrashReporter provides bounded fatal-crash evidence persistence for next-launch replay and bridges Objective-C exceptions through the shim target. Foreground, interval, batch-size, and lifecycle triggers all schedule flushes, while reachability changes defer delivery until the device can send again. Deeper automatic crash evidence collection and larger iOS background delivery strategies remain intentionally constrained by Apple's lifecycle rules and are not presented as guaranteed delivery.

Probes

Always-on probes buffer redacted diagnostic data locally and attach inline probe data to exception payloads:

DebugBundle.probe("checkout.tax", data: ["amount": amount, "country": country])

DebugBundle.probe("checkout.expensive_state", options: ProbeOptions(heavy: true)) {
    expensiveDiagnostics()
}

Heavy probes remain dormant until a matching remote directive or trigger token is active. Remote directives are fetched through GET /v1/sdk/config and ingestion-response piggybacking.

Privacy Defaults

Swift defaults are conservative for healthcare, finance, enterprise, and consumer apps:

  • request and response bodies are disabled by default
  • header capture is allowlist-based
  • screenshots, text fields, clipboard, contacts, keychain values, photos, precise location, IDFV, and advertising IDs are not captured by default
  • redaction happens before queue persistence or transport

Prefer explicit low-cardinality context values instead of raw user data:

DebugBundle.setContext("account_tier", value: "team")
DebugBundle.setContext("region", value: "eu")

Modules

ProductPurpose
DebugBundleCore client, facade, event envelopes, redaction, transport, queueing, capture policy, and probes
DebugBundleURLSessionURLSession instrumentation, trace propagation, and request capture
DebugBundleAlamofireAlamofire adapter for trace injection and request capture
DebugBundleUIKitUIApplication, UIScene, view-controller, and navigation helpers
DebugBundleSwiftUISwiftUI screen, scene-phase, navigation, and action breadcrumbs
DebugBundleCrashReporterNext-launch crash evidence replay and Objective-C exception bridging
DebugBundleSwiftLogSwiftLog LogHandler integration
DebugBundleTestSupportFake transports, queue inspection helpers, and mock ingestion support

Next Steps

On this page