Skip to main content

Configuring Backtrace for macOS

Configure Backtrace for your macOS project. This page defines the configuration settings, classes, and methods available with the Backtrace Cocoa SDK.

The macOS SDK shares the same core API as the iOS SDK. This page highlights macOS-specific configuration and notes where behavior differs. For the full API reference, see Configuring Backtrace for iOS.

Usage

import Cocoa
import Backtrace

@main
class AppDelegate: NSObject, NSApplicationDelegate {

func applicationDidFinishLaunching(_ aNotification: Notification) {
let backtraceCredentials = BacktraceCredentials(
endpoint: URL(string: "https://backtrace.io")!,
token: "token")

let backtraceDatabaseSettings = BacktraceDatabaseSettings()
backtraceDatabaseSettings.maxRecordCount = 1000
backtraceDatabaseSettings.maxDatabaseSize = 10
backtraceDatabaseSettings.retryInterval = 5
backtraceDatabaseSettings.retryLimit = 3
backtraceDatabaseSettings.retryBehaviour = .interval
backtraceDatabaseSettings.retryOrder = .stack

let backtraceConfiguration = BacktraceClientConfiguration(
credentials: backtraceCredentials,
dbSettings: backtraceDatabaseSettings,
reportsPerMin: 10,
allowsAttachingDebugger: false,
oomMode: .full)

BacktraceClient.shared = try? BacktraceClient(configuration: backtraceConfiguration)

// Set custom attributes
BacktraceClient.shared?.attributes = ["foo": "bar", "testing": true]

// Set delegate for event handling
BacktraceClient.shared?.delegate = self

// Enable breadcrumbs
BacktraceClient.shared?.enableBreadcrumbs()

// Enable error-free metrics
BacktraceClient.shared?.metrics.enable(settings: BacktraceMetricsSettings())
}
}

Advanced Usage

For more advanced usage of BacktraceClient, you can supply BacktraceClientConfiguration as a parameter. See the following example:

let backtraceCredentials = BacktraceCredentials(endpoint: URL(string: "https://backtrace.io")!, token: "token")
let configuration = BacktraceClientConfiguration(credentials: backtraceCredentials,
dbSettings: BacktraceDatabaseSettings(),
reportsPerMin: 10,
allowsAttachingDebugger: false,
oomMode: .full)
BacktraceClient.shared = try? BacktraceClient(configuration: configuration)

BacktraceClientConfiguration

Parameters

SettingDescriptionTypeDefault
credentials (Swift) or
initWithCredentials (Objective-C)
The BacktraceCredentials (endpoint URL and submission token) used to initialize the BacktraceClient.Parameter
dbSettingsThe BacktraceDatabaseSettings used to initialize the BacktraceDatabase.Parameter
reportsPerMinThe maximum number of reports per minute that BacktraceClient will send.Integer30
allowsAttachingDebuggerSpecifies whether to send reports when the debugger is connected.

The options are:
  • false (Swift) / NO (Objective-C): BacktraceClient will send reports when the debugger is connected.
  • true (Swift) / YES (Objective-C): BacktraceClient won't send reports when the debugger is connected.
Booleanfalse / NO
oomModeSpecifies how the SDK should handle OOM (Out-Of-Memory) detection. See OOM Detection Modes for details.

The options are:
  • .none (Swift) / BacktraceOomModeNone (Objective-C): Disables OOM detection.
  • .light (Swift) / BacktraceOomModeLight (Objective-C): Lightweight OOM report — current thread only, no symbolication.
  • .full (Swift) / BacktraceOomModeFull (Objective-C): Full OOM report — all threads, symbolicated.
BacktraceOomMode.none / BacktraceOomModeNone

Database Settings

BacktraceClient allows you to customize the initialization of BacktraceDatabase for local storage of error reports by supplying a BacktraceDatabaseSettings parameter, as follows:

let backtraceCredentials = BacktraceCredentials(endpoint: URL(string: "https://backtrace.io")!, token: "token")
let backtraceDatabaseSettings = BacktraceDatabaseSettings()
backtraceDatabaseSettings.maxRecordCount = 1000
backtraceDatabaseSettings.maxDatabaseSize = 10
backtraceDatabaseSettings.retryInterval = 5
backtraceDatabaseSettings.retryLimit = 3
backtraceDatabaseSettings.retryBehaviour = RetryBehaviour.interval
backtraceDatabaseSettings.retryOrder = RetryOder.queue
let backtraceConfiguration = BacktraceClientConfiguration(credentials: backtraceCredentials,
dbSettings: backtraceDatabaseSettings,
reportsPerMin: 10)
BacktraceClient.shared = try? BacktraceClient(configuration: backtraceConfiguration)

BacktraceDatabaseSettings

Parameters

SettingDescriptionTypeDefault
maxRecordCountThe maximum number of records stored in the database. If set to '0', then there is no record limit.Integer0
maxDatabaseSizeThe maximum size of the database in MB. If set to '0', then there is no size limit.Integer0
retryIntervalThe amount of time (in seconds) to wait before the next retry if unable to send a report.Integer5
retryLimitThe maximum number of retries to attempt if unable to send a report.Integer3
retryBehaviourThe retry behaviour if unable to send a report.

The options are:
  • interval: If unable to send a report, the database will retry based on the retryInterval.
  • none: If unable to send a report, the database will not retry.
Enuminterval
retryOrderThe retry order if unable to send a report.

The options are:
  • queue: The oldest reports are sent first (FIFO).
  • stack: The newest reports are sent first (LIFO).
Enumqueue

PLCrashReporter

BacktraceClient allows you to customize the configuration of the PLCrashReporter by injecting its instance as follows:

let backtraceCredentials = BacktraceCredentials(endpoint: URL(string: "https://backtrace.io")!, token: "token")
let backtraceConfiguration = BacktraceClientConfiguration(credentials: backtraceCredentials)
BacktraceClient.shared = try? BacktraceClient(
configuration: backtraceConfiguration,
crashReporter: BacktraceCrashReporter(config: PLCrashReporterConfig.defaultConfiguration()))
// or
BacktraceClient.shared = try? BacktraceClient(
configuration: backtraceConfiguration,
crashReporter: BacktraceCrashReporter(reporter: PLCrashReporter.shared()))

Custom Crash Directory

By default, PLCrashReporter stores .plcrash files in the app's standard cache directory. You can specify a custom directory to control where crash reports are written.

// Create a custom directory for crash reports
let baseURL = try FileManager.default.url(
for: .libraryDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: true)
let crashDir = baseURL.appendingPathComponent("btcrash", isDirectory: true)
try FileManager.default.createDirectory(
at: crashDir,
withIntermediateDirectories: true)

// Create a PLCrashReporterConfig with the custom basePath
guard let plcrashConfig = PLCrashReporterConfig(
signalHandlerType: .BSD,
symbolicationStrategy: .all,
basePath: crashDir.path) else {
fatalError("Could not create PLCrashReporterConfig")
}

let reporter = BacktraceCrashReporter(config: plcrashConfig)
BacktraceClient.shared = try? BacktraceClient(
configuration: backtraceConfiguration,
crashReporter: reporter)
note

On iOS, you can also set a FileProtectionType on the custom crash directory to control file access when the device is locked. See the iOS Custom Crash Directory documentation for details on FileProtectionType options. File protection is not applicable on macOS.

Handling Events

BacktraceClient allows you to subscribe to events produced before and after sending each report by attaching an object that follows the BacktraceClientDelegate protocol.

// assign `self` or any other object as a `BacktraceClientDelegate`
BacktraceClient.shared?.delegate = self

// handle events
func willSend(_ report: BacktraceCrashReport) -> (BacktraceCrashReport)
func willSendRequest(_ request: URLRequest) -> URLRequest
func serverDidFail(_ error: Error)
func serverDidRespond(_ result: BacktraceResult)
func didReachLimit(_ result: BacktraceResult)

For example, you can use BacktraceClientDelegate to modify a report before send:

func willSend(_ report: BacktraceReport) -> (BacktraceReport) {
report.attributes["added"] = "just before send"
return report
}

Attributes

You can add custom attributes to send alongside every crash and error report:

BacktraceClient.shared?.attributes = ["foo": "bar", "testing": true]

You can also specify a unique set of attributes for a specific report with the willSend(_:) method of BacktraceClientDelegate.

macOS-Specific System Attributes

The SDK automatically collects system attributes. The following attributes are collected differently on macOS compared to iOS:

AttributemacOS BehavioriOS Behavior
Hardware modelUses HW_MODEL (e.g., MacBookPro18,1)Uses HW_MACHINE (e.g., iPhone14,5)
OS nameReports macOSReports device systemName (e.g., iOS)
Screen infoUses NSScreen API — reports screen.main.width, screen.main.height, screen.main.scale, and screen countUses UIScreen API — reports screen.width, screen.height, screen.scale, plus native dimensions and brightness
Device orientationNot collected (not applicable)Collected via UIDevice
Battery stateNot collected via attributesCollected via UIDevice battery monitoring

File Attachments

All Reports

You can specify file attachments to send with every crash and error report. File attachments are specified as an array of URL that contain the path to the file.

guard let libraryDirectoryUrl = try? FileManager.default.url(
for: .libraryDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else {
throw CustomError.runtimeError
}

let fileUrl = libraryDirectoryUrl.appendingPathComponent("sample.txt")

var crashAttachments = Attachments()
crashAttachments.append(fileUrl)

BacktraceClient.shared?.attachments = crashAttachments

Per Report

You can specify file attachments to send for a specific report by supplying an array of file paths.

let filePath = Bundle.main.path(forResource: "test", ofType: "txt")!
BacktraceClient.shared?.send(attachmentPaths: [filePath]) { (result) in
print(result)
}

You can also specify a unique set of files for specific reports with the willSend(_:) method of BacktraceClientDelegate.

Error-Free Metrics

Error-free metrics allow you to determine:

  • How many of your unique users (i.e., unique device IDs) using your app are experiencing errors/crashes.
  • How many application sessions (i.e., individual application sessions from startup till shutdown/exit) of your app are experiencing errors/crashes.

You can track those metrics at-a-glance, as well as in detail to find out what kinds of errors/crashes are most common. For more information, see Stability Metrics Widgets.

Enabling Error-Free Metrics

BacktraceClient.shared?.metrics.enable(settings: BacktraceMetricsSettings())

iOS and macOS Only

Breadcrumbs allow you track events leading up to your crash, error, or other submitted object. When breadcrumbs are enabled, any captured breadcrumbs will automatically be attached as a file to your crash, error, or other submitted object (including native crashes).

note

Breadcrumbs are not supported on tvOS.

Enabling Breadcrumbs

BacktraceClient.shared?.enableBreadcrumbs()

Adding Manual Breadcrumbs

let attributes = ["My Attribute": "My Attribute Value"]
_ = BacktraceClient.shared?.addBreadcrumb("My Breadcrumb",
attributes: attributes,
type: .user,
level: .error)
caution

We recommend that you do not make calls to addBreadcrumb from performance-critical code paths.

Automatic Breadcrumbs on macOS

When breadcrumbs are enabled, the SDK automatically captures system events. The set of automatic breadcrumb events differs between macOS and iOS:

Automatic Breadcrumb TypemacOSiOS
Memory pressure (warning, critical)✅ Via DispatchSourceMemoryPressure✅ Via UIApplication.didReceiveMemoryWarningNotification
Battery / power source changes✅ Via IOKit power source monitoring✅ Via UIDevice battery notifications
Screen orientation changes❌ Not applicable
App state changes (foreground/background)
Phone call state changes❌ Not applicable✅ Via CallKit

On macOS, the SDK uses IOKit.ps (IOKit Power Sources) to monitor battery and power state changes, such as switching between AC power and battery, and charging level changes.

You can limit the types of automatic events that are captured by specifying which automatic breadcrumb types you want to enable:

let settings = BacktraceBreadcrumbSettings()
settings.breadcrumbTypes = [BacktraceBreadcrumbType.system, BacktraceBreadcrumbType.configuration]

OOM Detection Modes

OOM (Out-Of-Memory) detection is supported on macOS. The detection mechanism differs from iOS:

  • macOS: Uses DispatchSourceMemoryPressure to monitor for .warning and .critical memory pressure events.
  • iOS: Uses UIApplication.didReceiveMemoryWarningNotification.

The SDK provides configurable OOM detection through the BacktraceOomMode enum.

BacktraceOomMode

ModeSwiftObjective-CDescription
None.noneBacktraceOomModeNoneOOM detection is disabled. No launch-time overhead.
Light.lightBacktraceOomModeLightLightweight OOM report. Captures only the current thread without symbolication. Minimal performance impact.
Full.fullBacktraceOomModeFullFull OOM report. Captures all threads with symbolication. Provides the most diagnostic detail but has higher overhead at launch.

Choosing the Right Mode

Use CaseRecommended ModeRationale
Games and performance-critical apps.lightAvoids launch-time stalls from symbolication and thread enumeration. Games are especially sensitive to frame drops and launch latency.
Standard apps.fullProvides complete stack traces across all threads, making it easier to diagnose memory issues. The overhead at launch is acceptable for most apps.
Apps where launch time is critical.lightThe .light mode skips symbolication and runs on the current thread only, keeping launch fast.
OOM detection not needed.noneZero overhead. Use when OOM crashes are not a concern or are tracked through other means.

How It Works

  • .light mode captures a snapshot of the current thread at the moment of the low-memory warning. It skips symbolication, so the report is fast to generate but contains less detail. If the lightweight capture fails, it automatically falls back to .full mode.
  • .full mode captures all threads with full symbolication. This runs on a dedicated background dispatch queue (com.backtrace.oom) to avoid blocking the main thread, but the I/O and symbolication work can still impact launch performance.
  • Both modes capture the resident memory footprint at the time of the low-memory warning.

Usage

// Lightweight mode — recommended for games and performance-sensitive apps
let configuration = BacktraceClientConfiguration(
credentials: backtraceCredentials,
dbSettings: BacktraceDatabaseSettings(),
reportsPerMin: 10,
allowsAttachingDebugger: false,
oomMode: .light)

// Full mode — recommended for standard apps that need complete diagnostics
let configuration = BacktraceClientConfiguration(
credentials: backtraceCredentials,
dbSettings: BacktraceDatabaseSettings(),
reportsPerMin: 10,
allowsAttachingDebugger: false,
oomMode: .full)

Legacy API (detectOOM)

The detectOOM boolean parameter is deprecated but still supported for backward compatibility. It maps to the new oomMode as follows:

Legacy detectOOMEquivalent oomMode
false (default).none
true.full
// Legacy API (deprecated) — still works but prefer oomMode
let configuration = BacktraceClientConfiguration(
credentials: backtraceCredentials,
dbSettings: BacktraceDatabaseSettings(),
reportsPerMin: 10,
allowsAttachingDebugger: false,
detectOOM: true) // maps to oomMode: .full
note

The legacy detectOOM API does not support .light mode. To use lightweight OOM reporting, you must migrate to oomMode.