diff --git a/skills/sentry-cocoa-sdk/SKILL.md b/skills/sentry-cocoa-sdk/SKILL.md index 60628cf..c882d09 100644 --- a/skills/sentry-cocoa-sdk/SKILL.md +++ b/skills/sentry-cocoa-sdk/SKILL.md @@ -1,6 +1,6 @@ --- name: sentry-cocoa-sdk -description: Full Sentry SDK setup for Apple platforms (iOS, macOS, tvOS, watchOS, visionOS). Use when asked to "add Sentry to iOS", "add Sentry to Swift", "install sentry-cocoa", or configure error monitoring, tracing, profiling, session replay, or logging for Apple applications. Supports SwiftUI and UIKit. +description: Full Sentry SDK setup for Apple platforms (iOS, macOS, tvOS, watchOS, visionOS). Use when asked to "add Sentry to iOS", "add Sentry to Swift", "install sentry-cocoa", or configure error monitoring, tracing, profiling, session replay, logging, or metrics for Apple applications. Supports SwiftUI and UIKit. license: Apache-2.0 category: sdk-setup parent: sentry-sdk-setup @@ -16,12 +16,12 @@ Opinionated wizard that scans your Apple project and guides you through complete ## Invoke This Skill When - User asks to "add Sentry to iOS/macOS/tvOS" or "set up Sentry" in an Apple app -- User wants error monitoring, tracing, profiling, session replay, or logging in Swift/ObjC +- User wants error monitoring, tracing, profiling, session replay, or logging in Swift/ObjC, or metrics in Swift - User mentions `sentry-cocoa`, `SentrySDK`, or the Apple/iOS Sentry SDK - User wants to monitor crashes, app hangs, watchdog terminations, or performance -> **Note:** SDK versions and APIs below reflect Sentry docs at time of writing (sentry-cocoa 9.5.1). -> Always verify against [docs.sentry.io/platforms/apple/](https://docs.sentry.io/platforms/apple/) before implementing. +> **Note:** SDK versions and APIs below reflect sentry-cocoa 9.13.0. +> Before implementing, verify against the [Apple SDK docs](https://docs.sentry.io/platforms/apple/), [sentry-cocoa changelog](https://github.com/getsentry/sentry-cocoa/blob/main/CHANGELOG.md), and [sentry-cocoa source](https://github.com/getsentry/sentry-cocoa). Release notes may be ahead of docs for newly changed behavior. --- @@ -31,18 +31,21 @@ Run these commands to understand the project before making any recommendations: ```bash # Check existing Sentry dependency -grep -i sentry Package.swift Podfile Cartfile 2>/dev/null +grep -rEi "sentry|sentry-cocoa|SentrySPM|SentrySwiftUI" \ + --include="Package.swift" --include="Podfile" --include="Cartfile" \ + --include="Package.resolved" --include="project.pbxproj" . 2>/dev/null | head -20 # Detect UI framework (SwiftUI vs UIKit) -grep -rE "@main|struct.*App.*:.*App" --include="*.swift" . 2>/dev/null | head -5 -grep -rE "AppDelegate|UIApplicationMain" --include="*.swift" . 2>/dev/null | head -5 +grep -rE "@main|struct .*: App" --include="*.swift" . 2>/dev/null | head -5 +grep -rE "AppDelegate|UIApplicationMain|@UIApplicationDelegateAdaptor" --include="*.swift" . 2>/dev/null | head -5 # Detect platform and deployment targets -grep -E "platforms:|\.iOS|\.macOS|\.tvOS|\.watchOS|\.visionOS" Package.swift 2>/dev/null +grep -rE "platforms:|\\.iOS|\\.macOS|\\.tvOS|\\.watchOS|\\.visionOS|IPHONEOS_DEPLOYMENT_TARGET|MACOSX_DEPLOYMENT_TARGET|TVOS_DEPLOYMENT_TARGET|WATCHOS_DEPLOYMENT_TARGET|XROS_DEPLOYMENT_TARGET" \ + --include="Package.swift" --include="project.pbxproj" . 2>/dev/null | head -20 grep -E "platform :ios|platform :osx|platform :tvos|platform :watchos" Podfile 2>/dev/null # Detect logging -grep -rE "import OSLog|os\.log|CocoaLumberjack|DDLog" --include="*.swift" . 2>/dev/null | head -5 +grep -rE "import OSLog|import os\\.log|Logger\\(|CocoaLumberjack|DDLog" --include="*.swift" . 2>/dev/null | head -5 # Detect companion backend ls ../backend ../server ../api 2>/dev/null @@ -54,6 +57,7 @@ ls ../go.mod ../requirements.txt ../Gemfile ../package.json 2>/dev/null - SwiftUI (`@main App` struct) or UIKit (`AppDelegate`)? Determines init pattern. - Which Apple platforms? (Affects which features are available — see Platform Support Matrix.) - Existing logging library? (Enables structured log capture.) +- SwiftUI tracing import/product? `SentrySwiftUI` still exists but is deprecated in SDK 9.4.1+; prefer the main `Sentry` module for released binary products. - Companion backend? (Triggers Phase 4 cross-link for distributed tracing.) --- @@ -63,19 +67,19 @@ ls ../go.mod ../requirements.txt ../Gemfile ../package.json 2>/dev/null Based on what you found, present a concrete recommendation. Don't ask open-ended questions — lead with a proposal: **Recommended (core coverage):** -- ✅ **Error Monitoring** — always; crash reporting, app hangs, watchdog terminations, NSError/Swift errors -- ✅ **Tracing** — always for apps; auto-instruments app launch, network, UIViewController, file I/O, Core Data -- ✅ **Profiling** — production apps; continuous profiling with minimal overhead +- **Error Monitoring** — always; crash reporting, app hangs, watchdog terminations, NSError/Swift errors +- **Tracing** — always for apps; auto-instruments app launch, network, UIViewController, file I/O, Core Data +- **Profiling** — production iOS/macOS apps; UI profiling via `configureProfiling` **Optional (enhanced observability):** -- ⚡ **Session Replay** — user-facing apps; ⚠️ disabled by default on iOS 26+ (Liquid Glass rendering) -- ⚡ **Logging** — when structured log capture is needed -- ⚡ **User Feedback** — apps that want crash/error feedback forms from users +- **Session Replay** — user-facing iOS apps; verify masking on iOS 26+ / Liquid Glass builds +- **Logging** — when structured log capture is needed +- **Metrics** — Swift apps needing aggregate counters, gauges, or distributions +- **User Feedback** — apps that want crash/error feedback forms from users **Not available for Cocoa:** -- ❌ Metrics — use custom spans instead -- ❌ Crons — backend only -- ❌ AI Monitoring — JS/Python only +- Crons — backend only +- AI Monitoring — JS/Python only **Recommendation logic:** @@ -83,9 +87,10 @@ Based on what you found, present a concrete recommendation. Don't ask open-ended |---------|------------------| | Error Monitoring | **Always** — non-negotiable baseline | | Tracing | **Always for apps** — rich auto-instrumentation out of the box | -| Profiling | Production apps where performance matters | -| Session Replay | **iOS only** user-facing apps (check iOS 26+ caveat; not tvOS/macOS/watchOS/visionOS) | +| Profiling | iOS/macOS production apps where performance matters (not tvOS/watchOS/visionOS) | +| Session Replay | User-facing iOS apps; tvOS may work but is not officially supported | | Logging | Existing `os.log` / CocoaLumberjack usage, or structured logs needed | +| Metrics | Aggregate product or health signals that should not create issues; Swift only, SDK 9.12+ | | User Feedback | Apps wanting in-app bug reports with screenshots | Propose: *"I recommend Error Monitoring + Tracing + Profiling. Want me to also add Session Replay and Logging?"* @@ -117,52 +122,62 @@ https://github.com/getsentry/sentry-cocoa.git Or in `Package.swift`: ```swift -.package(url: "https://github.com/getsentry/sentry-cocoa", from: "9.5.1"), +.package(url: "https://github.com/getsentry/sentry-cocoa", from: "9.13.0"), ``` **SPM Products** — choose **exactly one** per target: | Product | Use Case | |---------|----------| -| `Sentry` | **Recommended** — static framework, fast app start | +| `Sentry` | **Recommended** — static framework, fast app start; includes SwiftUI APIs in SDK 9.4.1+ | | `Sentry-Dynamic` | Dynamic framework alternative | -| `SentrySwiftUI` | SwiftUI view performance tracking (`SentryTracedView`) | +| `SentrySwiftUI` | Legacy/deprecated re-export for SwiftUI APIs; use only when maintaining older setup | | `Sentry-WithoutUIKitOrAppKit` | watchOS, app extensions, CLI tools (Swift < 6.1) | -| `SentrySPM` + `NoUIFramework` trait | watchOS, app extensions, macOS CLI tools (**Swift 6.1+ / Xcode 16.3+** only) | +| `SentrySPM` + `NoUIFramework` trait | Source build without UIKit/AppKit for CLI/headless targets (**SDK 9.7+ / Swift 6.1+ / Xcode 26.4+** for Xcode UI) | -> ⚠️ Xcode allows selecting multiple products — choose only one. +> Warning: Xcode allows selecting multiple products — choose only one. +> +> If using `SentrySPM` from source, current source-build projects may import `SentrySwift` instead of `Sentry`; verify the module name in the target. Released binary products use `import Sentry`. **Swift 6.1+ trait-based opt-out of UIKit/AppKit** (requires `Package@swift-6.1.swift` manifest): ```swift // Package.swift (Swift 6.1+) -.package(url: "https://github.com/getsentry/sentry-cocoa", from: "9.5.1"), +.package( + url: "https://github.com/getsentry/sentry-cocoa", + from: "9.13.0", + traits: ["NoUIFramework"] +), // In your target's dependencies: -.product(name: "SentrySPM", package: "sentry-cocoa", condition: .when(traits: ["NoUIFramework"])) +.product(name: "SentrySPM", package: "sentry-cocoa") ``` -This is the preferred opt-out path for macOS command-line tools and app extensions on Swift 6.1+. For Swift < 6.1 continue using `Sentry-WithoutUIKitOrAppKit`. +This is the preferred opt-out path for command-line/headless targets on Swift 6.1+. It compiles the SDK from source so the trait can remove UIKit/AppKit/SwiftUI linkage. For Swift < 6.1 continue using `Sentry-WithoutUIKitOrAppKit`. -> **Note:** Package traits are visible in the Xcode UI starting with **Xcode 26.4+** (currently in beta). On older Xcode versions, traits still work when declared in `Package.swift` but won't appear in the GUI. +> **Note:** Package traits are visible in the Xcode UI starting with **Xcode 26.4+**. On older Xcode versions, traits still work when declared in `Package.swift` but won't appear in the GUI. -**Option 3 — CocoaPods:** +**Option 3 — CocoaPods (deprecated; prefer SPM):** ```ruby -platform :ios, '11.0' +platform :ios, '15.0' use_frameworks! target 'YourApp' do - pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '9.5.1' + pod 'Sentry', :git => 'https://github.com/getsentry/sentry-cocoa.git', :tag => '9.13.0' end ``` +Sentry plans to stop publishing CocoaPods releases at the end of June 2026; use this only for existing CocoaPods projects. + > **Known issue (Xcode 14+):** Sandbox `rsync.samba` error → Target Settings → "Enable User Script Sandbox" → `NO`. --- ### Quick Start — Recommended Init -Full config enabling the most features with sensible defaults. Add before any other code at app startup. +Full iOS app config enabling the most common features with sensible defaults. Add before any other code at app startup. + +For macOS, watchOS, app extensions, or `NoUIFramework` builds, omit options that are unavailable for that platform (`sessionReplay`, screenshots/view hierarchy, user-feedback UI, UIKit tracing, and profiling on tvOS/watchOS/visionOS). Keep the core `dsn`, environment, error monitoring, tracing, logs, and metrics settings that compile for the detected target. **SwiftUI — App entry point:** ```swift @@ -176,11 +191,13 @@ struct MyApp: App { options.dsn = ProcessInfo.processInfo.environment["SENTRY_DSN"] ?? "https://examplePublicKey@o0.ingest.sentry.io/0" options.environment = ProcessInfo.processInfo.environment["SENTRY_ENVIRONMENT"] - options.releaseName = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String + ?? "production" + // releaseName defaults to "@+"; set only if you need a custom release. // Error monitoring (on by default — explicit for clarity) options.enableCrashHandler = true - options.enableAppHangTrackingV2 = true + options.enableAppHangTracking = true + options.enableReportNonFullyBlockingAppHangs = true options.enableWatchdogTerminationTracking = true options.attachScreenshot = true options.attachViewHierarchy = true @@ -195,12 +212,15 @@ struct MyApp: App { $0.lifecycle = .trace } - // Session Replay (disabled on iOS 26+ by default — safe to configure) - options.sessionReplay.sessionSampleRate = 1.0 + // Session Replay. Keep production sampling conservative and verify masking on iOS 26+. + options.sessionReplay.sessionSampleRate = 0.1 options.sessionReplay.onErrorSampleRate = 1.0 // Logging (SDK 9.0.0+ top-level; use options.experimental.enableLogs in 8.x) options.enableLogs = true + + // Metrics are enabled by default in SDK 9.12+. Set false only to opt out. + options.enableMetrics = true } } @@ -225,10 +245,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { options.dsn = ProcessInfo.processInfo.environment["SENTRY_DSN"] ?? "https://examplePublicKey@o0.ingest.sentry.io/0" options.environment = ProcessInfo.processInfo.environment["SENTRY_ENVIRONMENT"] - options.releaseName = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String + ?? "production" + // releaseName defaults to "@+"; set only if you need a custom release. options.enableCrashHandler = true - options.enableAppHangTrackingV2 = true + options.enableAppHangTracking = true + options.enableReportNonFullyBlockingAppHangs = true options.enableWatchdogTerminationTracking = true options.attachScreenshot = true options.attachViewHierarchy = true @@ -241,18 +263,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate { $0.lifecycle = .trace } - options.sessionReplay.sessionSampleRate = 1.0 + options.sessionReplay.sessionSampleRate = 0.1 options.sessionReplay.onErrorSampleRate = 1.0 // Logging (SDK 9.0.0+ top-level; use options.experimental.enableLogs in 8.x) options.enableLogs = true + + // Metrics are enabled by default in SDK 9.12+. Set false only to opt out. + options.enableMetrics = true } return true } } ``` -> ⚠️ SDK initialization must occur on the **main thread**. +> Warning: SDK initialization must occur on the **main thread**. --- @@ -265,8 +290,9 @@ Walk through features one at a time. Load the reference file for each, follow it | Error Monitoring | `${SKILL_ROOT}/references/error-monitoring.md` | Always (baseline) | | Tracing | `${SKILL_ROOT}/references/tracing.md` | App launch, network, UIViewController perf | | Profiling | `${SKILL_ROOT}/references/profiling.md` | Production perf-sensitive apps | -| Session Replay | `${SKILL_ROOT}/references/session-replay.md` | User-facing iOS/tvOS apps | +| Session Replay | `${SKILL_ROOT}/references/session-replay.md` | User-facing iOS apps; tvOS only with caveat | | Logging | `${SKILL_ROOT}/references/logging.md` | Structured log capture needed | +| Metrics | `${SKILL_ROOT}/references/metrics.md` | Aggregate counters, gauges, distributions | | User Feedback | `${SKILL_ROOT}/references/user-feedback.md` | In-app bug reporting wanted | For each feature: `Read ${SKILL_ROOT}/references/.md`, follow steps exactly, verify it works. @@ -279,13 +305,14 @@ For each feature: `Read ${SKILL_ROOT}/references/.md`, follow steps exa | Option | Type | Default | Purpose | |--------|------|---------|---------| -| `dsn` | `String` | `""` | SDK disabled if empty; reads `SENTRY_DSN` env var | -| `environment` | `String` | `""` | e.g., `"production"`; reads `SENTRY_ENVIRONMENT` | -| `releaseName` | `String` | `""` | e.g., `"my-app@1.0.0"`; reads `SENTRY_RELEASE` | +| `dsn` | `String?` | `nil` | SDK disabled if empty; macOS can read `SENTRY_DSN`, other Apple platforms must set explicitly | +| `environment` | `String` | `"production"` | e.g., `"production"` | +| `releaseName` | `String?` | bundle-derived | Defaults to `@+` | | `debug` | `Bool` | `false` | Verbose SDK output — **disable in production** | | `sendDefaultPii` | `Bool` | `false` | Include IP, user info from active integrations | | `enableCrashHandler` | `Bool` | `true` | Master switch for crash reporting | -| `enableAppHangTrackingV2` | `Bool` | `true` (9.0+) | Differentiates fully/non-fully blocked hangs | +| `enableAppHangTracking` | `Bool` | `true` | Master switch for app hang tracking | +| `enableReportNonFullyBlockingAppHangs` | `Bool` | `true` | Report non-fully-blocking hangs on supported UI platforms | | `appHangTimeoutInterval` | `Double` | `2.0` | Seconds before classifying as hang | | `enableWatchdogTerminationTracking` | `Bool` | `true` | Track watchdog kills (iOS, tvOS, Mac Catalyst) | | `attachScreenshot` | `Bool` | `false` | Capture screenshot on error | @@ -293,39 +320,42 @@ For each feature: `Read ${SKILL_ROOT}/references/.md`, follow steps exa | `tracesSampleRate` | `NSNumber?` | `nil` | Transaction sample rate (`nil` = tracing disabled); Swift auto-boxes `Double` literals (e.g. `1.0` → `NSNumber`) | | `tracesSampler` | `Closure` | `nil` | Dynamic per-transaction sampling (overrides rate) | | `enableAutoPerformanceTracing` | `Bool` | `true` | Master switch for auto-instrumentation | -| `tracePropagationTargets` | `[String]` | `[".*"]` | Hosts/regex that receive distributed trace headers | +| `tracePropagationTargets` | `[Any]` | all requests | Strings or `NSRegularExpression` values that receive distributed trace headers | | `enableCaptureFailedRequests` | `Bool` | `true` | Auto-capture HTTP 5xx errors as events | | `enableNetworkBreadcrumbs` | `Bool` | `true` | Breadcrumbs for outgoing HTTP requests | -| `inAppInclude` | `[String]` | `[]` | Module prefixes treated as "in-app" code | +| `add(inAppInclude:)` | Method | bundle executable | Add module prefixes treated as "in-app" code | | `maxBreadcrumbs` | `Int` | `100` | Max breadcrumbs per event | | `sampleRate` | `Float` | `1.0` | Error event sample rate | | `beforeSend` | `Closure` | `nil` | Hook to mutate/drop error events | -| `onCrashedLastRun` | `Closure` | `nil` | Called on next launch after a crash | +| `onLastRunStatusDetermined` | `Closure` | `nil` | Called after SDK determines previous launch crash status | | `strictTraceContinuation` | `Bool` | `false` | Reject incoming traces from other orgs; validates `org_id` in baggage headers (sentry-cocoa ≥9.10.0) | | `orgId` | `String?` | `nil` | Organization ID for strict trace validation; auto-parsed from DSN host (e.g. `o123.ingest.sentry.io` → `"123"`) if not set explicitly | +| `enableLogs` | `Bool` | `false` | Enable structured logs | +| `enableMetrics` | `Bool` | `true` | Enable Swift Metrics API (SDK 9.12+) | ### Environment Variables | Variable | Maps to | Purpose | |----------|---------|---------| -| `SENTRY_DSN` | `dsn` | Data Source Name | -| `SENTRY_RELEASE` | `releaseName` | App version (e.g., `my-app@1.0.0`) | -| `SENTRY_ENVIRONMENT` | `environment` | Deployment environment | +| `SENTRY_DSN` | `dsn` | macOS fallback only; set explicitly on iOS/tvOS/watchOS/visionOS | +| `SENTRY_RELEASE` | `releaseName` | Do not assume automatic Cocoa fallback; set explicitly if needed | +| `SENTRY_ENVIRONMENT` | `environment` | Do not assume automatic Cocoa fallback; set explicitly if needed | ### Platform Feature Support Matrix | Feature | iOS | tvOS | macOS | watchOS | visionOS | |---------|-----|------|-------|---------|----------| -| Crash Reporting | ✅ | ✅ | ✅ | ✅ | ✅ | -| App Hangs V2 | ✅ | ✅ | ❌ | ❌ | ❌ | -| Watchdog Termination | ✅ | ✅ | ❌ | ❌ | ❌ | -| App Start Tracing | ✅ | ✅ | ❌ | ❌ | ✅ | -| UIViewController Tracing | ✅ | ✅ | ❌ | ❌ | ✅ | -| SwiftUI Tracing | ✅ | ✅ | ✅ | ❌ | ✅ | -| Network Tracking | ✅ | ✅ | ✅ | ❌ | ✅ | -| Profiling | ✅ | ✅ | ✅ | ❌ | ✅ | -| Session Replay | ✅ | ❌ | ❌ | ❌ | ❌ | -| MetricKit | ✅ (15+) | ❌ | ✅ (12+) | ❌ | ❌ | +| Crash Reporting | Yes | Yes | Yes | No | Yes | +| App Hangs | Yes | Yes | Yes | No | Yes | +| Watchdog Termination | Yes | Yes | No | No | Yes | +| App Start Tracing | Yes | Yes | No | No | Yes | +| UIViewController Tracing | Yes | Yes | No | No | Yes | +| SwiftUI Tracing | Yes | Yes | Yes | No | Yes | +| Network Tracking | Yes | Yes | Yes | No | Yes | +| Profiling | Yes | No | Yes | No | No | +| Session Replay | Yes | Unofficial | No | No | No | +| MetricKit | Yes (15+) | No | Yes (12+) | No | No | +| Metrics API | Yes | Yes | Yes | Verify | Yes | --- @@ -363,6 +393,8 @@ options.configureProfiling = { options.sessionReplay.sessionSampleRate = 0.1 // 10% continuous options.sessionReplay.onErrorSampleRate = 1.0 // 100% on error (keep high) +options.enableLogs = true +options.enableMetrics = true // default true in SDK 9.12+ options.debug = false // never in production ``` @@ -385,10 +417,10 @@ If a backend is found, configure `tracePropagationTargets` to enable distributed | Backend detected | Suggest skill | Trace header support | |-----------------|--------------|---------------------| -| Go (`go.mod`) | `sentry-go-sdk` | ✅ automatic | -| Python (`requirements.txt`) | `sentry-python-sdk` | ✅ automatic | -| Ruby (`Gemfile`) | `sentry-ruby-sdk` | ✅ automatic | -| Node.js backend (`package.json`) | `sentry-node-sdk` (or `sentry-express-sdk`) | ✅ automatic | +| Go (`go.mod`) | `sentry-go-sdk` | Automatic | +| Python (`requirements.txt`) | `sentry-python-sdk` | Automatic | +| Ruby (`Gemfile`) | `sentry-ruby-sdk` | Automatic | +| Node.js backend (`package.json`) | `sentry-node-sdk` (or `sentry-express-sdk`) | Automatic | --- @@ -399,12 +431,13 @@ If a backend is found, configure `tracePropagationTargets` to enable distributed | Events not appearing | Set `debug: true`, verify DSN format, ensure init is on main thread | | Crashes not captured | **Run without debugger attached** — debugger intercepts signals | | App hangs not reported | Auto-disabled when debugger attached; check `appHangTimeoutInterval` | -| Session Replay not recording | Check iOS version — disabled by default on iOS 26+ (Liquid Glass); verify `sessionSampleRate > 0` | +| Session Replay not recording | Verify `sessionSampleRate > 0` or `onErrorSampleRate > 0`; on iOS 26+ verify masking and any manual Liquid Glass gating | | Tracing data missing | Confirm `tracesSampleRate > 0`; check `enableAutoPerformanceTracing = true` | | Profiling data missing | Verify `sessionSampleRate > 0` in `configureProfiling`; for `.trace` lifecycle, tracing must be enabled | | `rsync.samba` build error (CocoaPods) | Target Settings → "Enable User Script Sandbox" → `NO` | | Multiple SPM products selected | Choose **only one** of `Sentry`, `Sentry-Dynamic`, `SentrySwiftUI`, `Sentry-WithoutUIKitOrAppKit`, or `SentrySPM` (with `NoUIFramework` trait on Swift 6.1+) | -| `inAppExclude` compile error | Removed in SDK 9.0.0 — use `inAppInclude` only | +| `inAppExclude` compile error | Removed in SDK 9.0.0 — use `options.add(inAppInclude:)` | +| `enableAppHangTrackingV2` compile error | Removed in SDK 9.0.0 — use `enableAppHangTracking`; V2 behavior is default where supported | | Watchdog termination not tracked | Requires `enableCrashHandler = true` (it is by default) | | Network breadcrumbs missing | Requires `enableSwizzling = true` (it is by default) | | `profilesSampleRate` compile error | Removed in SDK 9.0.0 — use `configureProfiling` closure instead | diff --git a/skills/sentry-cocoa-sdk/references/error-monitoring.md b/skills/sentry-cocoa-sdk/references/error-monitoring.md index 6ba8f77..472a9e9 100644 --- a/skills/sentry-cocoa-sdk/references/error-monitoring.md +++ b/skills/sentry-cocoa-sdk/references/error-monitoring.md @@ -1,7 +1,7 @@ # Error Monitoring — Sentry Cocoa SDK -> Minimum SDK: `sentry-cocoa` v7.0.0+ -> Swift Error improvements: v8.7.0+ +> Minimum SDK: `sentry-cocoa` v7.0.0+ +> Swift Error improvements: v8.7.0+ > HTTP client error capture: v8.0.0+ ## Configuration @@ -11,10 +11,11 @@ | `enableCrashHandler` | `Bool` | `true` | Master switch for crash reporting (signal handlers, Mach exceptions, C++) | | `sampleRate` | `Float` (0.0–1.0) | `1.0` | Percentage of error events sent | | `attachStacktrace` | `Bool` | `true` | Attach stack traces to all captured messages | +| `attachAllThreads` | `Bool` | `false` | Attach full stack traces for all threads (SDK 9.9+) | | `maxBreadcrumbs` | `Int` | `100` | Max breadcrumbs per event | | `enableAppHangTracking` | `Bool` | `true` | Detect main thread unresponsiveness | | `appHangTimeoutInterval` | `Double` | `2.0` | Seconds before a hang is reported | -| `enableAppHangTrackingV2` | `Bool` | `true` (v9+) | Differentiates fully/non-fully-blocking hangs | +| `enableReportNonFullyBlockingAppHangs` | `Bool` | `true` | Include non-fully-blocking hangs where V2 is supported | | `enableWatchdogTerminationTracking` | `Bool` | `true` | Track OS watchdog kills via heuristics | | `enableCaptureFailedRequests` | `Bool` | `true` | Auto-capture HTTP client errors as Sentry events | | `failedRequestStatusCodes` | `[HttpStatusCodeRange]` | `[500–599]` | Status code ranges that trigger error capture | @@ -119,8 +120,8 @@ SentrySDK.start { options in options.enableAppHangTracking = true options.appHangTimeoutInterval = 2.0 // default; avoid values < 0.1 - // V2: differentiates fully vs non-fully blocking hangs (default in v9+) - options.enableAppHangTrackingV2 = true + // V2 is the default in v9+ where supported; this option controls whether + // less-actionable non-fully-blocking hangs are reported. options.enableReportNonFullyBlockingAppHangs = true } @@ -235,10 +236,9 @@ SentrySDK.start { options in return nil } // Suppress app hang events - // Note: V1 (enableAppHangTracking) uses exception type "App Hanging" - // V2 (enableAppHangTrackingV2, default in 9.0+) may use a different - // type — inspect event.exceptions?.first?.type in beforeSend to confirm - if event.exceptions?.first?.type == "App Hanging" { + // V1/macOS may use "App Hanging"; V2 uses the more specific values + // listed above. Inspect event.exceptions?.first?.type in beforeSend. + if event.exceptions?.first?.type?.contains("App Hang") == true { return nil } // Scrub sensitive data @@ -325,7 +325,7 @@ When `enableCrashHandler = true` (default), the SDK installs: - **C++ exception handlers** — `std::terminate` interception - **Objective-C uncaught exception handler** — `NSSetUncaughtExceptionHandler` -> ⚠️ Always test crash reporting **without a debugger attached**. The debugger intercepts signals and prevents the SDK from capturing crashes. +> Warning: Always test crash reporting **without a debugger attached**. The debugger intercepts signals and prevents the SDK from capturing crashes. ### macOS — uncaught NSException reporting diff --git a/skills/sentry-cocoa-sdk/references/logging.md b/skills/sentry-cocoa-sdk/references/logging.md index 79a6faf..88c6f8e 100644 --- a/skills/sentry-cocoa-sdk/references/logging.md +++ b/skills/sentry-cocoa-sdk/references/logging.md @@ -1,6 +1,6 @@ # Logging — Sentry Cocoa SDK -> Minimum SDK (experimental): `sentry-cocoa` v8.55.0+ +> Minimum SDK (experimental): `sentry-cocoa` v8.55.0+ > Minimum SDK (stable): `sentry-cocoa` v9.0.0+ ## Configuration @@ -59,7 +59,7 @@ logger.error("Payment failed", attributes: ["amount": 99.99]) logger.fatal("Connection pool exhausted", attributes: ["activeConnections": 100]) ``` -Supported attribute value types: `String`, `Int`, `Double`, `Bool`. +Supported Swift attribute value types include `String`, `Bool`, `Int`, `Double`, `Float`, arrays, and sets; other values are converted to strings. ### Log levels (severity order) @@ -103,19 +103,19 @@ SentrySDK.start { options in if log.level == .debug && options.environment == "production" { return nil } // Enrich all logs with app version - var mutableLog = log - mutableLog.attributes["app.version"] = - Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String - return mutableLog + if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String { + log.attributes["app.version"] = SentryAttribute(string: version) + } + return log } } ``` Available on `SentryLog`: -- `log.level` — `SentryLevel` (`.trace`, `.debug`, `.info`, `.warning`, `.error`, `.fatal`) -- `log.message` — `String` +- `log.level` — `SentryLog.Level` (`.trace`, `.debug`, `.info`, `.warn`, `.error`, `.fatal`) +- `log.body` — `String` - `log.timestamp` — `Date` -- `log.attributes` — `[String: Any]` +- `log.attributes` — `[String: SentryAttribute]` ### Automatic default attributes @@ -188,7 +188,7 @@ SentrySDK.logger.info("User signed in", | Logs not appearing in Sentry | Verify `options.enableLogs = true` (v9+) or `options.experimental.enableLogs = true` (v8.55+) | | Logs only partially appearing | Logs may be lost during crashes; this is a known SDK limitation | | `SentrySDK.logger` not found | Requires v8.55.0+; check SPM/CocoaPods version | -| Attributes not queryable | Only `String`, `Int`, `Double`, and `Bool` are supported attribute value types | +| Attributes not queryable | Prefer `String`, `Bool`, `Int`, `Double`, `Float`, arrays, or sets; convert complex objects to stable strings | | `beforeSendLog` not called | Ensure you set it before `SentrySDK.start` completes and `enableLogs = true` | | Too many logs overwhelming Sentry | Use `beforeSendLog` to filter by level; set minimum level for production | | Logs missing user context | Call `SentrySDK.setUser(...)` before logging to attach user identity automatically | diff --git a/skills/sentry-cocoa-sdk/references/metrics.md b/skills/sentry-cocoa-sdk/references/metrics.md new file mode 100644 index 0000000..631f3e7 --- /dev/null +++ b/skills/sentry-cocoa-sdk/references/metrics.md @@ -0,0 +1,122 @@ +# Metrics — Sentry Cocoa SDK + +> Minimum SDK: experimental in v9.4.0+, generally available in v9.12.0+ +> Swift only; Objective-C metrics API is not currently available. +> Metrics are enabled by default in v9.12.0+. + +Use metrics for aggregate counters, gauges, and distributions that should not create Sentry issues. Do not duplicate automatic tracing, app hangs, MetricKit diagnostics, or error events. + +## Configuration + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `enableMetrics` | `Bool` | `true` | Enable or disable metrics | +| `beforeSendMetric` | `((SentryMetric) -> SentryMetric?)?` | `nil` | Filter or mutate metrics before send; return `nil` to drop | + +For SDK 9.4.0-9.11.x, metrics used `options.experimental.enableMetrics` and `options.experimental.beforeSendMetric`. Those experimental options were removed in 9.12.0; use the top-level options above. + +## Code Examples + +### Basic setup + +```swift +import Sentry + +SentrySDK.start { options in + options.dsn = "___PUBLIC_DSN___" + options.enableMetrics = true // default in SDK 9.12+ +} +``` + +### Counter + +Counters track discrete occurrences. `count` does not accept a unit. + +```swift +SentrySDK.metrics.count(key: "button.click") + +SentrySDK.metrics.count( + key: "link.created", + value: 1, + attributes: [ + "source": "share_extension", + "is_favorite": false + ] +) +``` + +### Gauge + +Gauges track current state. + +```swift +SentrySDK.metrics.gauge( + key: "queue.depth", + value: 42, + attributes: ["queue": "sync"] +) +``` + +### Distribution + +Distributions track measured values where percentiles are useful. + +```swift +SentrySDK.metrics.distribution( + key: "qr.render.duration", + value: 187.5, + unit: .millisecond, + attributes: [ + "cache_hit": true, + "image_size": "1024" + ] +) +``` + +### beforeSendMetric + +```swift +SentrySDK.start { options in + options.dsn = "___PUBLIC_DSN___" + options.beforeSendMetric = { metric in + var metric = metric + + if case let .boolean(drop)? = metric.attributes["drop_me"], drop { + return nil + } + + metric.attributes["processed"] = .boolean(true) + metric.attributes["app_area"] = .string("links") + return metric + } +} +``` + +## Attribute Types + +Metric attributes use `SentryAttributeValue` at the capture API and `SentryAttributeContent` inside `beforeSendMetric`. + +Supported capture values: +- Scalar: `String`, `Bool`, `Int`, `Double`, `Float` +- Arrays: `[String]`, `[Bool]`, `[Int]`, `[Double]`, `[Float]` +- Sets: `Set`, `Set`, `Set`, `Set`, `Set` (SDK 9.13+) + +Use stable, low-cardinality attributes. Avoid URLs, IDs, user-entered names, or unbounded strings unless they are intentionally scrubbed and useful for grouping. + +## Best Practices + +- Use metrics for aggregate product and app-health signals, not exceptions or stack traces. +- Keep metric names lowercase and dot-delimited, such as `link.created` or `network.reachability.changed`. +- Prefer distributions for durations and sizes, gauges for current state, and counters for occurrences. +- Avoid metrics that duplicate automatic spans, failed request events, app hangs, watchdog terminations, or MetricKit diagnostics. +- Keep `enableMetrics = true` unless the app has a policy or volume reason to disable metrics. + +## Troubleshooting + +| Issue | Solution | +|-------|----------| +| `enableMetrics` compile error | Requires SDK 9.12+; on 9.4-9.11 use `experimental.enableMetrics` or upgrade | +| Metric not sent | Verify `SentrySDK.start` ran and `enableMetrics` is true | +| Count with `unit` fails | `count` has no `unit` parameter; use `gauge` or `distribution` if units are needed | +| Objective-C compile issue | Metrics are Swift-only | +| Too many unique series | Reduce high-cardinality attributes and metric names | diff --git a/skills/sentry-cocoa-sdk/references/profiling.md b/skills/sentry-cocoa-sdk/references/profiling.md index 37901a9..14c53ac 100644 --- a/skills/sentry-cocoa-sdk/references/profiling.md +++ b/skills/sentry-cocoa-sdk/references/profiling.md @@ -1,7 +1,8 @@ # Profiling — Sentry Cocoa SDK -> Minimum SDK for UI Profiling (`configureProfiling`): `sentry-cocoa` v8.49.0+ -> Minimum SDK for stable `configureProfiling` API: v9.0.0+ +> Minimum SDK for UI Profiling (`configureProfiling`): `sentry-cocoa` v8.49.0+ +> Minimum SDK for stable `configureProfiling` API: v9.0.0+ +> Supported platforms: iOS and macOS. Not supported on tvOS, watchOS, or visionOS. > **All legacy profiling APIs (`profilesSampleRate`, `enableAppLaunchProfiling`, continuous beta) were removed in v9.0.0.** ## Configuration @@ -9,7 +10,7 @@ | Option | Type | Default | Description | |--------|------|---------|-------------| | `configureProfiling` | `((SentryProfileOptions) -> Void)?` | `nil` | Closure to configure UI Profiling (v8.49.0+) | -| `sessionSampleRate` | `Double` (0.0–1.0) | `0` | Fraction of user sessions to profile; evaluated once per session | +| `sessionSampleRate` | `Float` (0.0–1.0) | `0` | Fraction of user sessions to profile; evaluated once per session | | `lifecycle` | `SentryProfileLifecycle` | `.manual` | `.trace` (auto) or `.manual` (explicit start/stop) | | `profileAppStarts` | `Bool` | `false` | Profile from the earliest possible lifecycle stage on next launch | @@ -149,7 +150,7 @@ For CI/CD, set `SENTRY_AUTH_TOKEN` as an environment variable. // BEFORE (removed in v9.0.0) SentrySDK.start { options in options.tracesSampleRate = 1.0 - options.profilesSampleRate = 1.0 // ❌ no longer exists + options.profilesSampleRate = 1.0 // Removed: no longer exists } // AFTER (v9.0.0+) @@ -157,7 +158,7 @@ SentrySDK.start { options in options.tracesSampleRate = 1.0 options.configureProfiling = { $0.sessionSampleRate = 1.0 - $0.lifecycle = .trace // ✅ equivalent behaviour + $0.lifecycle = .trace // Equivalent behavior } } ``` @@ -174,9 +175,9 @@ MetricKit delivers hang diagnostic payloads on iOS 15+ and macOS 12+. Starting w |----------|----------------------| | iOS | 15+ | | macOS | 12+ | -| tvOS | ❌ | -| watchOS | ❌ | -| visionOS | ❌ | +| tvOS | No | +| watchOS | No | +| visionOS | No | ## Best Practices diff --git a/skills/sentry-cocoa-sdk/references/session-replay.md b/skills/sentry-cocoa-sdk/references/session-replay.md index f020143..da33021 100644 --- a/skills/sentry-cocoa-sdk/references/session-replay.md +++ b/skills/sentry-cocoa-sdk/references/session-replay.md @@ -1,8 +1,9 @@ # Session Replay — Sentry Cocoa SDK -> Minimum SDK: `sentry-cocoa` v8.31.1+ -> View Renderer V2 (default): v8.50.0+ -> iOS 26 auto-disable safeguard: v8.57.0+ +> Minimum SDK: `sentry-cocoa` v8.31.1+ +> View Renderer V2 (default): v8.50.0+ +> Official support: iOS 16+ with UIKit and SwiftUI. tvOS 16+ may work but is not officially supported. +> SDK 9.12.0+ runs on iOS 26 Liquid Glass; verify masking for your app. ## Configuration @@ -21,6 +22,12 @@ | `sessionReplay.errorReplayDuration` | `TimeInterval` | `30` | Seconds of buffer kept before an error | | `sessionReplay.sessionSegmentDuration` | `TimeInterval` | `5` | Seconds per upload segment | | `sessionReplay.maximumDuration` | `TimeInterval` | `3600` | Maximum session duration (60 min) | +| `experimental.enableReplayNetworkDetailsCapturing` | `Bool` | `false` | Capture request/response details in replays (SDK 9.12+) | +| `sessionReplay.networkDetailAllowUrls` | `[SentryUrlMatchable]` | `[]` | URL allowlist for replay network details | +| `sessionReplay.networkDetailDenyUrls` | `[SentryUrlMatchable]` | `[]` | URL denylist for replay network details | +| `sessionReplay.networkCaptureBodies` | `Bool` | `true` | Capture bodies for allowed URLs when network details are enabled | +| `sessionReplay.networkRequestHeaders` | `[String]` | default safe headers | Request headers to capture for allowed URLs | +| `sessionReplay.networkResponseHeaders` | `[String]` | default safe headers | Response headers to capture for allowed URLs | ## Code Examples @@ -54,12 +61,12 @@ SentrySDK.start { options in What is masked by default: -- ✅ All text content (`maskAllText = true`) -- ✅ All images (`maskAllImages = true`) -- ✅ User input fields (always masked, regardless of settings) -- ✅ Video players -- ✅ WebViews -- ❌ Bundled image assets (considered low PII risk — shown in replay) +- Masked: all text content (`maskAllText = true`) +- Masked: all images (`maskAllImages = true`) +- Masked: user input fields (always masked, regardless of settings) +- Masked: video players +- Masked: WebViews +- Not masked by default: bundled image assets (considered low PII risk; shown in replay) ### SwiftUI view modifiers @@ -113,6 +120,29 @@ SentrySDK.replay.showMaskPreview(0.5) // 50% opacity #endif ``` +### Network details in replays (SDK 9.12+) + +Network details are opt-in and require both the experimental flag and an allowlist: + +```swift +SentrySDK.start { options in + options.experimental.enableReplayNetworkDetailsCapturing = true + options.sessionReplay.networkDetailAllowUrls = [ + "api.myapp.com", + ".*\\.myapp\\.com" + ] + options.sessionReplay.networkDetailDenyUrls = [ + "api.myapp.com/oauth", + "api.myapp.com/payment" + ] + options.sessionReplay.networkCaptureBodies = false + options.sessionReplay.networkRequestHeaders = ["Content-Type", "X-Request-ID"] + options.sessionReplay.networkResponseHeaders = ["Content-Type", "X-Request-ID"] +} +``` + +Keep request and response bodies disabled unless you have explicitly reviewed them for sensitive data. + ### Exclude views from subtree traversal For views that cause crashes or performance issues during replay capture: @@ -148,22 +178,33 @@ if ProcessInfo.processInfo.isLowPowerModeEnabled { --- -## ⚠️ iOS 26 / Xcode 26 / Liquid Glass Caveat +## iOS 26 / Xcode 26 / Liquid Glass -Apple's **Liquid Glass** rendering engine in iOS 26 breaks the SDK's view-snapshotting approach, causing unreliable masking and potential PII leaks. +There is version-specific behavior here: -**Starting with v8.57.0**, Session Replay is **automatically and silently disabled** when both: -- App is running on **iOS 26.0 or later** -- App was **compiled with Xcode 26.0 or later** +- SDK 8.57.0 through 9.11.x auto-disabled Session Replay on iOS 26 Liquid Glass builds to avoid masking risks. +- SDK 9.12.0+ removed that safeguard after redaction fixes; Session Replay records on iOS 26 again. +- If your app needs to keep replay disabled for Liquid Glass, gate `sessionSampleRate` and `onErrorSampleRate` yourself. -Replay continues to work if: -- The device runs iOS < 26 -- The app was built with Xcode < 26 -- `UIDesignRequiresCompatibility = YES` is set in `Info.plist` +Example manual gate: -**SDKs older than v8.57.0** do **not** include this safeguard and may crash or leak PII on iOS 26. Upgrade immediately. +```swift +var sessionRate: Float = 0.1 +var errorRate: Float = 1.0 + +if #available(iOS 26.0, *) { + let compatibilityMode = Bundle.main.object(forInfoDictionaryKey: "UIDesignRequiresCompatibility") as? Bool ?? false + let xcodeVersion = Int(Bundle.main.object(forInfoDictionaryKey: "DTXcode") as? String ?? "") ?? 0 + let liquidGlassActive = xcodeVersion >= 2600 && !compatibilityMode + if liquidGlassActive { + sessionRate = 0 + errorRate = 0 + } +} -Track the fix at [getsentry/sentry-cocoa#6390](https://github.com/getsentry/sentry-cocoa/issues/6390). +options.sessionReplay.sessionSampleRate = sessionRate +options.sessionReplay.onErrorSampleRate = errorRate +``` --- @@ -183,17 +224,18 @@ Track the fix at [getsentry/sentry-cocoa#6390](https://github.com/getsentry/sent ## Best Practices -- Set `maskAllText = true` and `maskAllImages = true` (both default) — only unmasked explicitly what's safe to show +- Set `maskAllText = true` and `maskAllImages = true` (both default) — only unmask content that is explicitly safe to show - Use `.sentryReplayUnmask()` sparingly on known-safe content rather than globally disabling masking - Start with `onErrorSampleRate = 1.0` and `sessionSampleRate = 0` to capture replays only on errors (lowest overhead) - Test masking on real devices — use `SentrySDK.replay.showMaskPreview()` in DEBUG builds to verify +- Re-test masking on iOS 26+ Liquid Glass after every SDK or Xcode upgrade ## Troubleshooting | Issue | Solution | |-------|----------| | No replays appearing | Verify `sessionSampleRate > 0` or `onErrorSampleRate > 0`; both default to `0` | -| Replay disabled on iOS 26 | Expected — SDK 8.57.0+ auto-disables for safety; set `UIDesignRequiresCompatibility = YES` in `Info.plist` to build with Xcode < 26 compatibility | +| Replay disabled on iOS 26 | SDK 8.57.0–9.11.x auto-disabled Liquid Glass builds; SDK 9.12+ records again unless you gate sample rates yourself | | PII visible in replay | Verify `maskAllText = true` and `maskAllImages = true`; check `.sentryReplayUnmask()` isn't applied too broadly | | Scrolling jank during replay | Enable `enableFastViewRendering = true`; switch to `quality = .low`; consider disabling on low-end devices | | Replay stops after 60 minutes | Expected — `maximumDuration = 3600` seconds is the default cap | diff --git a/skills/sentry-cocoa-sdk/references/tracing.md b/skills/sentry-cocoa-sdk/references/tracing.md index 6fa0782..1054524 100644 --- a/skills/sentry-cocoa-sdk/references/tracing.md +++ b/skills/sentry-cocoa-sdk/references/tracing.md @@ -1,7 +1,7 @@ # Tracing — Sentry Cocoa SDK -> Minimum SDK: `sentry-cocoa` v7.0.0+ -> SwiftUI instrumentation stable: v8.17.0+ +> Minimum SDK: `sentry-cocoa` v7.0.0+ +> SwiftUI instrumentation stable: v8.17.0+ > File I/O manual tracing extensions: v8.48.0+ ## Configuration @@ -20,10 +20,10 @@ | `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 | +| `tracePropagationTargets` | `[Any]` | all requests | Strings or `NSRegularExpression` values 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 | +| `orgId` | `String?` | auto-parsed from DSN | Organization ID used for strict trace continuation validation; auto-parsed from the DSN host | ## Code Examples @@ -166,11 +166,11 @@ Child spans produced (sequential): | 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. +> Warning: If more than **5 seconds** elapse between transaction start and app-start end, app start spans are **not attached** to avoid misassociation. ### URLSession Network Tracking -**Platforms:** All +**Platforms:** All **Note:** `NSURLConnection` is **not** supported — only `NSURLSession`. Automatically adds HTTP spans to any active scope-bound transaction. @@ -182,7 +182,7 @@ options.enableNetworkTracking = false ### UIViewController Lifecycle Tracing -**Platforms:** iOS, tvOS, Mac Catalyst +**Platforms:** iOS, tvOS, Mac Catalyst **Not available for:** SwiftUI (use `SentryTracedView` instead) - Transaction operation: `ui.load` @@ -221,10 +221,10 @@ TTFD span status: ### SwiftUI Instrumentation -**Package:** `SentrySwiftUI` (separate SPM product — do not also add `Sentry`) +For SDK 9.4.1+, SwiftUI tracing APIs are available from the main `Sentry` module. The `SentrySwiftUI` product/module still exists as a deprecated re-export for older setups. ```swift -import SentrySwiftUI +import Sentry // Option 1: wrapper var body: some View { @@ -251,9 +251,11 @@ SentryTracedView("Content", waitForFullDisplay: true) { } ``` +If maintaining an older project that already uses the `SentrySwiftUI` product, `import SentrySwiftUI` still works in SDK 9.x but should be migrated to `import Sentry` before the next major version. Source-build `SentrySPM` projects may expose the module as `SentrySwift`; verify imports against the selected product. + ### Slow & Frozen Frames -**Platforms:** iOS, tvOS, Mac Catalyst +**Platforms:** iOS, tvOS, Mac Catalyst Tracked automatically during any active transaction. Appears as Mobile Vitals in the Sentry Performance UI. | Threshold | Classification | @@ -263,7 +265,7 @@ Tracked automatically during any active transaction. Appears as Mobile Vitals in ### User Interaction Tracing -**Platforms:** iOS, tvOS, Mac Catalyst +**Platforms:** iOS, tvOS, Mac Catalyst **Not available for:** SwiftUI Creates a transaction for every UIControl tap/click. @@ -288,7 +290,7 @@ options.enableUserInteractionTracing = false ### File I/O Tracing (NSData) -**Platforms:** All +**Platforms:** All Tracks `NSData` read/write operations as spans. ```swift @@ -326,7 +328,7 @@ Span operations created: ### Core Data Tracing -**Platforms:** All +**Platforms:** All Instruments `NSManagedObjectContext` fetch and save operations. ```swift @@ -365,7 +367,7 @@ SentrySDK.start { options in > **`enablePropagateTraceparent` requires 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. +> Warning: Both headers must be included in CORS allowlists and must not be blocked by proxies or firewalls. ### Strict Trace Continuation (SDK 9.x+) @@ -379,7 +381,7 @@ SentrySDK.start { options in // 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 + // options.orgId = "12345" } ``` @@ -389,18 +391,18 @@ SentrySDK.start { options in | 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+) | ✅ | +| `tracesSampleRate` | Yes | Yes | Yes | Yes | +| App Start Tracing | Yes | Yes | No | Yes | +| UIViewController Lifecycle | Yes | Yes | No | Yes | +| TTID / TTFD | Yes | Yes | No | Yes | +| Slow & Frozen Frames | Yes | Yes | No | Yes | +| Network Tracking (URLSession) | Yes | Yes | Yes | Yes | +| File I/O Tracing | Yes | Yes | Yes | Yes | +| Core Data Tracing | Yes | Yes | Yes | Yes | +| User Interaction Tracing | Yes | Yes | No | Yes | +| SwiftUI (`SentryTracedView`) | Yes (13+) | Yes | Yes | Yes | +| Prewarmed App Start | Yes (15+) | No | No | No | +| NSFileManager Swizzling | Yes (18+) | Yes (18+) | Yes (15+) | Yes | --- @@ -410,7 +412,7 @@ SentrySDK.start { options in - Use `tracesSampler` (not `tracesSampleRate`) for route-specific or user-tier-based sampling - Use `bindToScope: true` when starting a transaction so child spans created anywhere in the call stack are automatically linked - Always `finish()` spans — unfinished spans are silently dropped -- Use `SentryTracedView` from the `SentrySwiftUI` package for SwiftUI screens (UIViewController tracing doesn't apply) +- Use `SentryTracedView` or `.sentryTrace()` from the main `Sentry` module for SwiftUI screens on SDK 9.4.1+ (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 @@ -425,5 +427,5 @@ SentrySDK.start { options in | 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` | +| `SentryTracedView` not available | SDK 9.4.1+: use `import Sentry` with the `Sentry` product; older/deprecated setups may need the `SentrySwiftUI` product | | High-cardinality transaction names | UIViewController transactions use class name — expected; custom transactions should use stable names | diff --git a/skills/sentry-cocoa-sdk/references/user-feedback.md b/skills/sentry-cocoa-sdk/references/user-feedback.md index 04cd085..2fbf0fa 100644 --- a/skills/sentry-cocoa-sdk/references/user-feedback.md +++ b/skills/sentry-cocoa-sdk/references/user-feedback.md @@ -1,6 +1,6 @@ # User Feedback — Sentry Cocoa SDK -> Minimum SDK: `sentry-cocoa` v8.46.0+ +> Minimum SDK: `sentry-cocoa` v8.46.0+ > Self-hosted Sentry server: 24.4.2+ ## Configuration @@ -29,7 +29,7 @@ import Sentry SentrySDK.start { options in options.dsn = "___PUBLIC_DSN___" - options.configureUserFeedback { config in + options.configureUserFeedback = { config in config.onSubmitSuccess = { data in // data keys: "message", "name", "email", "attachments" print("Feedback submitted: \(data["message"] ?? "")") @@ -86,11 +86,8 @@ func sceneDidBecomeActive(_ scene: UIScene) { ```swift SentrySDK.start { options in - options.configureUserFeedback { config in - config.configureWidget { widget in - widget.autoInject = false // disable the default floating button - widget.customButton = myButton // tapping this button opens the form - } + options.configureUserFeedback = { config in + config.customButton = myButton // tapping this button opens the form } } ``` @@ -98,7 +95,7 @@ SentrySDK.start { options in ### Trigger via shake gesture or screenshot ```swift -options.configureUserFeedback { config in +options.configureUserFeedback = { config in config.useShakeGesture = true // shake to open form config.showFormForScreenshots = true // auto-open after screenshot } @@ -138,8 +135,8 @@ SentrySDK.capture(feedback: .init( ### Form customisation ```swift -options.configureUserFeedback { config in - config.configureForm { form in +options.configureUserFeedback = { config in + config.configureForm = { form in form.formTitle = "Share Your Feedback" form.submitButtonLabel = "Send Feedback" form.cancelButtonLabel = "Never Mind" @@ -155,8 +152,8 @@ options.configureUserFeedback { config in ### Widget placement and labels ```swift -options.configureUserFeedback { config in - config.configureWidget { widget in +options.configureUserFeedback = { config in + config.configureWidget = { widget in widget.labelText = "Give Feedback" widget.location = [.bottom, .trailing] // anchor edges widget.showIcon = true @@ -168,14 +165,14 @@ options.configureUserFeedback { config in ### Theme customisation ```swift -options.configureUserFeedback { config in - config.theme { theme in - theme.submitBackground = .init(color: .systemBlue) +options.configureUserFeedback = { config in + config.configureTheme = { theme in + theme.submitBackground = .systemBlue theme.fontFamily = "SF Pro Rounded" } - config.darkTheme { theme in - theme.background = .init(color: .black) - theme.submitBackground = .init(color: .systemPurple) + config.configureDarkTheme = { theme in + theme.background = .black + theme.submitBackground = .systemPurple } } ``` @@ -205,12 +202,12 @@ import Sentry SentrySDK.start { options in options.dsn = "___PUBLIC_DSN___" - options.configureUserFeedback { config in + options.configureUserFeedback = { config in config.showFormForScreenshots = true config.useShakeGesture = false config.animations = true - config.configureForm { form in + config.configureForm = { form in form.formTitle = "Report a Bug" form.submitButtonLabel = "Send Bug Report" form.isNameRequired = true @@ -219,26 +216,26 @@ SentrySDK.start { options in form.useSentryUser = true } - config.configureWidget { widget in + config.configureWidget = { widget in widget.labelText = "Report a Bug" widget.location = [.bottom, .trailing] widget.autoInject = true } - config.theme { theme in - theme.submitBackground = .init(color: .systemBlue) + config.configureTheme = { theme in + theme.submitBackground = .systemBlue } - config.darkTheme { theme in - theme.background = .init(color: .black) + config.configureDarkTheme = { theme in + theme.background = .black } config.onFormOpen = { print("Feedback form opened") } config.onFormClose = { print("Feedback form closed") } config.onSubmitSuccess = { data in - print("✅ Feedback: \(data["message"] ?? "")") + print("Feedback: \(data["message"] ?? "")") } config.onSubmitError = { error in - print("❌ Submission failed: \(error)") + print("Submission failed: \(error)") } } } @@ -255,7 +252,8 @@ SentrySDK.start { options in | `showIcon` | `Bool` | `true` | | `labelText` | `String?` | `"Report a Bug"` | | `widgetAccessibilityLabel` | `String` | `labelText` | -| `customButton` | `UIButton?` | `nil` | + +`customButton` is on `SentryUserFeedbackConfiguration`, not `SentryUserFeedbackWidgetConfiguration`. If it is set, `configureWidget` is ignored. ## SentryUserFeedbackFormConfiguration Reference @@ -280,7 +278,7 @@ SentrySDK.start { options in - Set `useSentryUser = true` (default) and call `SentrySDK.setUser(...)` so the form pre-fills name and email — reduces friction - Enable `showFormForScreenshots = true` — users often take screenshots when something goes wrong; it's a natural trigger -- Disable `autoInject` and use `widget.customButton = myButton` to match your app's design language +- Disable `autoInject` for SwiftUI, or set `config.customButton = myButton` to bind the form to your own UIKit button - Use `config.onSubmitSuccess` to show a native confirmation (toast/alert) after the Sentry form dismisses - If collecting feedback from a known event ID, use `associatedEventId` to link the feedback to the specific issue in Sentry - Add `tags` on the configuration to automatically tag all feedback events with context (e.g., app version, screen name)