Minimum SDK:
sentry-cocoav7.0.0+
SwiftUI instrumentation stable: v8.17.0+
File I/O manual tracing extensions: v8.48.0+
| Option | Type | Default | Description |
|---|---|---|---|
tracesSampleRate |
Double (0.0–1.0) |
nil |
Uniform sample rate; mutually exclusive with tracesSampler |
tracesSampler |
(SentrySamplingContext) -> NSNumber |
nil |
Dynamic per-transaction sampling; overrides tracesSampleRate |
enableAutoPerformanceTracing |
Bool |
true |
Master switch for all automatic instrumentation |
enableUIViewControllerTracing |
Bool |
true |
UIViewController lifecycle spans |
enableUserInteractionTracing |
Bool |
true |
Transactions for UIControl tap/click events |
enableNetworkTracking |
Bool |
true |
URLSession HTTP request spans |
enableFileIOTracing |
Bool |
true |
NSData / FileManager file I/O spans |
enableCoreDataTracing |
Bool |
true |
Core Data fetch/save spans |
enableTimeToFullDisplayTracing |
Bool |
false |
TTFD span; requires SentrySDK.reportFullyDisplayed() |
enablePreWarmedAppStartTracing |
Bool |
true |
Prewarmed cold/warm start tracing (iOS 15+) |
enableDataSwizzling |
Bool |
true |
NSData swizzling for automatic file I/O tracing |
enableFileManagerSwizzling |
Bool |
false |
NSFileManager swizzling (experimental; needed for iOS 18+) |
tracePropagationTargets |
[String] |
[".*"] |
Hosts/regex for outgoing distributed trace headers |
enableSwizzling |
Bool |
true |
Master switch for method swizzling (required by several auto-instrumentation features) |
strictTraceContinuation |
Bool |
false |
Only continue an incoming trace when orgId matches; prevents cross-org trace continuation (SDK 9.x+) |
orgId |
UInt64? |
auto-parsed from DSN | Organization ID used for strict trace continuation validation; auto-parsed from the DSN host |
import Sentry
SentrySDK.start { options in
options.dsn = "___PUBLIC_DSN___"
options.tracesSampleRate = 1.0 // 100% in dev; lower for production (e.g., 0.2)
}SentrySDK.start { options in
options.dsn = "___PUBLIC_DSN___"
options.tracesSampler = { context in
// Never sample next-launch transactions
if context.isForNextAppLaunch { return 0 }
// Always sample checkout
if context.customSamplingContext?["flow"] as? String == "checkout" { return 1.0 }
// Default: 25%
return 0.25
}
}import Sentry
func performCheckout() {
let transaction = SentrySDK.startTransaction(
name: "checkout",
operation: "perform-checkout",
bindToScope: true // makes it accessible via SentrySDK.span
)
let validationSpan = transaction.startChild(
operation: "validation",
description: "validating shopping cart"
)
validateShoppingCart()
validationSpan.finish()
let processSpan = transaction.startChild(
operation: "process",
description: "processing payment"
)
do {
try processPayment()
processSpan.finish()
transaction.finish()
} catch {
SentrySDK.capture(error: error)
processSpan.finish(status: .internalError)
transaction.finish(status: .internalError)
}
}func processPayment() {
// Grab the transaction bound to scope (or start a standalone one)
let span = SentrySDK.span ?? SentrySDK.startTransaction(
name: "processPayment",
operation: "task"
)
let child = span.startChild(operation: "payment.gateway")
defer { child.finish() }
// payment logic...
}let transaction = SentrySDK.startTransaction(name: "sync", operation: "task")
transaction.setData(value: "incremental", key: "sync.type")
transaction.setData(value: 42, key: "sync.item_count")
transaction.setData(value: true, key: "sync.force")
transaction.setData(value: ["a", "b"], key: "sync.queues")
let span = transaction.startChild(operation: "db.fetch")
span.setData(value: "orders", key: "db.table")
span.finish()
transaction.finish()let span = SentrySDK.span
span?.setMeasurement(name: "memory_used",
value: 64,
unit: MeasurementUnitInformation.megabyte)
span?.setMeasurement(name: "profile_load_time",
value: 1.3,
unit: MeasurementUnitDuration.second)
span?.setMeasurement(name: "items_processed", value: 128)All features are enabled once tracesSampleRate > 0 (or tracesSampler is set). Disable all at once with enableAutoPerformanceTracing = false.
Platforms: iOS, tvOS, Mac Catalyst
Measures process creation → first rendered frame. Start type classifications:
| Type | Description |
|---|---|
cold |
First launch, post-reboot, or post-update |
warm |
Any other process creation |
cold.prewarmed |
Cold start with OS pre-warm (iOS 15+) |
warm.prewarmed |
Warm start with OS pre-warm (iOS 15+) |
Child spans produced (sequential):
| Span | Measures |
|---|---|
| Pre Runtime Init | Process start → runtime init |
| Runtime Init to Pre Main Initializers | Runtime init → pre-main setup |
| UIKit Init | Pre-main → Sentry SDK startup |
| Application Init | SDK startup → didFinishLaunchingNotification |
| Initial Frame Render | didFinishLaunchingNotification → first CADisplayLink callback (v9+) |
⚠️ If more than 5 seconds elapse between transaction start and app-start end, app start spans are not attached to avoid misassociation.
Platforms: All
Note: NSURLConnection is not supported — only NSURLSession.
Automatically adds HTTP spans to any active scope-bound transaction.
// Disable
options.enableNetworkTracking = falsePlatforms: iOS, tvOS, Mac Catalyst
Not available for: SwiftUI (use SentryTracedView instead)
- Transaction operation:
ui.load - Transaction name:
Your_App.MainViewController - Auto-generated child spans:
loadView,viewDidLoad,viewWillAppear,viewDidAppear - Time to Initial Display (TTID) span:
ui.load.initial-display
// Include framework view controllers
options.add(inAppInclude: "MyFramework")
// Exclude specific view controllers
options.swizzleClassNameExcludes = ["MyModalViewController"]
// Disable entirely
options.enableUIViewControllerTracing = false// Enable globally
options.enableTimeToFullDisplayTracing = true
// In your view controller, signal when async content is fully loaded:
SentrySDK.reportFullyDisplayed()TTFD span status:
| Scenario | Status |
|---|---|
reportFullyDisplayed() called |
.ok |
| Not finished within 30 seconds | .deadlineExceeded; duration = TTID duration |
| Called before view appears | Reported time = TTID time |
Package: SentrySwiftUI (separate SPM product — do not also add Sentry)
import SentrySwiftUI
// Option 1: wrapper
var body: some View {
SentryTracedView("My Awesome Screen") {
List { /* content */ }
}
}
// Option 2: modifier
var body: some View {
List { /* content */ }
.sentryTrace("My Awesome Screen")
}
// With TTFD (v8.44.0+)
SentryTracedView("Content", waitForFullDisplay: true) {
VStack { /* async content */ }
.onAppear {
Task {
data = await loadData()
SentrySDK.reportFullyDisplayed()
}
}
}Platforms: iOS, tvOS, Mac Catalyst
Tracked automatically during any active transaction. Appears as Mobile Vitals in the Sentry Performance UI.
| Threshold | Classification |
|---|---|
| > 16 ms per frame | Slow frame |
| > 700 ms per frame | Frozen frame |
Platforms: iOS, tvOS, Mac Catalyst
Not available for: SwiftUI
Creates a transaction for every UIControl tap/click.
- Transaction operation:
ui.actionorui.action.click - Transaction name:
YourApp_LoginViewController.loginButton idleTimeout: 3000 ms — transaction finishes if no child spans within 3 seconds- Transactions with no child spans are dropped
// Create child spans inside a tap handler:
func onLoginTapped() {
let span = SentrySDK.span
let child = span?.startChild(operation: "loadUserProfile")
// ... work ...
child?.finish()
}
// Disable
options.enableUserInteractionTracing = falsePlatforms: All
Tracks NSData read/write operations as spans.
options.enableFileIOTracing = true // default
// iOS 18+ / macOS 15+: NSFileManager no longer backed by NSData
// Enable experimental NSFileManager swizzling:
options.enableFileManagerSwizzling = true // experimental, v9.0.0+Manual tracing extensions (v8.48.0+) — only create spans when an active transaction exists:
// Data read/write
let data = try Data(contentsOfWithSentryTracing: url)
try data.writeWithSentryTracing(to: url)
// FileManager
let fm = FileManager.default
fm.createFileWithSentryTracing(atPath: path, contents: data)
try fm.moveItemWithSentryTracing(at: src, to: dst)
try fm.copyItemWithSentryTracing(at: src, to: dst)
try fm.removeItemWithSentryTracing(at: url)Span operations created:
| Method | Span Op |
|---|---|
Data.init(contentsOf:) |
file.read |
data.write(to:) / createFile |
file.write |
moveItem |
file.rename |
copyItem |
file.copy |
removeItem |
file.delete |
Platforms: All
Instruments NSManagedObjectContext fetch and save operations.
options.enableCoreDataTracing = true // default
// Disable
options.enableCoreDataTracing = falseSentry injects two headers into outgoing NSURLSession requests when the host matches tracePropagationTargets:
| Header | Purpose |
|---|---|
sentry-trace |
Carries trace ID, span ID, and sampled flag |
baggage |
Carries Dynamic Sampling Context key-value pairs |
SentrySDK.start { options in
options.dsn = "___PUBLIC_DSN___"
options.tracesSampleRate = 1.0
// Only propagate to your own backend (default: all requests)
options.tracePropagationTargets = [
"api.myapp.com",
".*\\.myapp\\.com" // regex supported
]
// Also add W3C traceparent header (requires sentry-cocoa 9.0.0+)
options.enablePropagateTraceparent = true
}
enablePropagateTraceparentrequires sentry-cocoa 9.0.0+. It is not available in 8.x.
⚠️ Both headers must be included in CORS allowlists and must not be blocked by proxies or firewalls.
Enable strictTraceContinuation to reject incoming traces from other Sentry organizations. When enabled, the SDK validates that the sentry-trace header's organization ID matches your DSN's organization before continuing the trace:
SentrySDK.start { options in
options.dsn = "___PUBLIC_DSN___"
options.tracesSampleRate = 1.0
// Only accept traces from your own Sentry organization
options.strictTraceContinuation = true
// orgId is auto-parsed from DSN host; override only if needed:
// options.orgId = 12345
}| Feature | iOS | tvOS | macOS | Mac Catalyst |
|---|---|---|---|---|
tracesSampleRate |
✅ | ✅ | ✅ | ✅ |
| App Start Tracing | ✅ | ✅ | ❌ | ✅ |
| UIViewController Lifecycle | ✅ | ✅ | ❌ | ✅ |
| TTID / TTFD | ✅ | ✅ | ❌ | ✅ |
| Slow & Frozen Frames | ✅ | ✅ | ❌ | ✅ |
| Network Tracking (URLSession) | ✅ | ✅ | ✅ | ✅ |
| File I/O Tracing | ✅ | ✅ | ✅ | ✅ |
| Core Data Tracing | ✅ | ✅ | ✅ | ✅ |
| User Interaction Tracing | ✅ | ✅ | ❌ | ✅ |
SwiftUI (SentryTracedView) |
✅ (13+) | ✅ | ✅ | ✅ |
| Prewarmed App Start | ✅ (15+) | ❌ | ❌ | ❌ |
| NSFileManager Swizzling | ✅ (18+) | ✅ (18+) | ✅ (15+) | ✅ |
- Start with
tracesSampleRate = 1.0in development; lower to0.1–0.2in production - Use
tracesSampler(nottracesSampleRate) for route-specific or user-tier-based sampling - Use
bindToScope: truewhen starting a transaction so child spans created anywhere in the call stack are automatically linked - Always
finish()spans — unfinished spans are silently dropped - Use
SentryTracedViewfrom theSentrySwiftUIpackage for SwiftUI screens (UIViewController tracing doesn't apply) - Call
SentrySDK.reportFullyDisplayed()only after your async data has been rendered — not just loaded - Avoid setting
tracePropagationTargets = [".*"]in production if you make requests to third-party services not using Sentry
| Issue | Solution |
|---|---|
| No transactions appearing | Ensure tracesSampleRate > 0 or tracesSampler returns > 0 |
| Spans missing from transactions | Ensure span.finish() is called; check bindToScope: true for cross-function spans |
| App start spans not attached | Gap between transaction start and app-start end exceeded 5 seconds; check slow initialization |
| UIViewController tracing missing | Verify enableSwizzling = true; check class is not in swizzleClassNameExcludes |
| Network spans not appearing | Requires active scope-bound transaction; verify enableNetworkTracking = true and enableSwizzling = true |
| Distributed trace not linking to backend | Propagate both sentry-trace AND baggage headers; add them to CORS allowlist |
| File I/O spans missing on iOS 18+ | Enable enableFileManagerSwizzling = true (experimental) or use manual WithSentryTracing extensions |
SentryTracedView not available |
Add SentrySwiftUI SPM product — it's a separate package from Sentry |
| High-cardinality transaction names | UIViewController transactions use class name — expected; custom transactions should use stable names |