iOS SDK observability reference
This LaunchDarkly observability plugin is available for early access
This LaunchDarkly observability plugin is currently available in Early Access, and APIs are subject to change until a 1.x version is released.
This topic documents how to get started with the LaunchDarkly observability plugin for the iOS SDK.
The iOS SDK supports the observability plugin for error monitoring, logging, and tracing, and the session replay plugin for recording user sessions.
SDK quick links
LaunchDarkly SDKs are open source. In addition to this reference guide, we provide source and a sample application:
Prerequisites and dependencies
This reference guide assumes that you are somewhat familiar with the LaunchDarkly iOS SDK.
The observability plugin is compatible with the iOS SDK, version 9.14.0 and later, and is only available if you are using Swift.
Get started
Follow these steps to get started:
- Install the plugin
- Initialize the iOS SDK client
- Configure the plugin options
- Configure product analytics event collection
- Track screen views
- Configure session replay
- Explore supported features
- Review observability data in LaunchDarkly
Install the plugin
LaunchDarkly uses a plugin to the iOS SDK to provide observability.
The first step is to make both the SDK and the observability plugin available as dependencies.
Here’s how:
Then, import the plugin into your code:
Initialize the client
Next, initialize the SDK and the plugin.
To initialize, you need your LaunchDarkly environment’s mobile key. This authorizes your application to connect to a particular environment within LaunchDarkly. To learn more, read Initialize the client in the Android SDK reference guide.
Here’s how to initialize the SDK and plugin:
Configure the plugin options
You can configure options for the observability plugin when you initialize the SDK. The plugin constructor takes an optional object with the configuration details.
Here is an example:
Configuration options
The ObservabilityOptions struct provides the following parameters:
- isEnabled: When
false, the plugin installs but exports no telemetry. Defaults totrue. - serviceName: The service name for the application. Defaults to “observability-swift”.
- serviceVersion: The service version for the application. Defaults to “0.1.0”.
- otlpEndpoint: The endpoint URL for the OpenTelemetry Protocol (OTLP) exporter. Defaults to the LaunchDarkly endpoint.
- resourceAttributes: Additional OpenTelemetry resource attributes to include in telemetry data.
- customHeaders: Custom headers to include with OTLP exports.
- sessionBackgroundTimeout: How long the app can stay in the background, in seconds, before the current session ends. Defaults to 15 minutes (900 seconds).
- isDebug: Enables additional logging for debugging. Defaults to
false. - logsApiLevel: The minimum severity of logs to export. Use
.noneto disable log collection. Defaults to.info. - tracesApi: Controls trace collection. Defaults to
.enabled. - metricsApi: Controls metric collection. Defaults to
.enabled. - crashReporting: Controls automatic crash reporting. Defaults to
.enabled. - tracingOrigins: Which outgoing request origins propagate distributed tracing headers. Defaults to
.disabled. - urlBlocklist: URL patterns to exclude from automatic
URLSessioninstrumentation. Defaults to an empty array. - contextFriendlyName: A human-readable name to attach to the LaunchDarkly context for this session.
- instrumentation: Controls automatic instrumentation. To learn more, read Instrumentation options.
- analytics: Controls which product analytics events the plugin emits as OpenTelemetry spans. To learn more, read Configure product analytics event collection.
Instrumentation options
The instrumentation option controls which automatic instrumentations the plugin runs. Pass an Instrumentation value, or use the .enabled and .disabled presets to turn all of them on or off at once.
The Instrumentation options are:
- urlSession: Instruments
URLSessionrequests. Defaults to.disabled. - userTaps: Runs tap detection. The
analytics.tapsoption separately controls whether the plugin publishes detected taps asclickspans. IfuserTapsis.disabled, the plugin publishes noclickspans regardless of theanalytics.tapsvalue. Neither option affects session replay capture. Defaults to.enabled. - memory: Records memory usage metrics. Defaults to
.disabled. - memoryWarnings: Records memory warning events. Defaults to
.disabled. - cpu: Records CPU usage metrics. Defaults to
.disabled. - launchTimes: Emits launch-time performance telemetry, including the
app.startspan event that carries the cold or warm startup dimension on theapp_launchspan. Defaults to.enabled. - screens: Automatically detects screen changes by swizzling
UIViewController. Screen detection drives both the automaticscreen_viewspan and the session replayNavigateevents. Defaults to.enabled. Theanalytics.screenViewsoption gatesscreen_viewspans.
Here is an example that turns off automatic screen detection while leaving other instrumentation at its default:
For more information on plugin options, read Configuration for client-side observability.
Configure product analytics event collection
The iOS observability plugin can record the following product analytics events as OpenTelemetry spans:
- Taps (automatic): A
clickspan for each user tap, with details about the tapped element and screen location. Enabled by default. - Track events (manual): A
trackspan when your code callstrack(key:properties:metricValue:). To learn more, read Recording product analytics events. - Screen views (automatic and manual): A
screen_viewspan when a screen appears, either detected automatically or recorded manually when your code callstrackScreenView(). To learn more, read Recording product analytics events. - App lifecycle (automatic): An
app_foregroundorapp_backgroundspan as the app moves between the foreground and background states. Enabled by default. - App launches (automatic): An
app_launchspan once per process launch, with the launch type and version information, plus anapp.startspan event that records the cold or warm startup dimension. Enabled by default. To learn more, read App launch events.
All product analytics span events also include information about the LaunchDarkly context that generated the event.
Use the generated span events to create custom product analytics charts, such as time series and funnels. To learn more, read Product analytics events.
The plugin records all event types by default. To disable all product analytics events, set analytics to .disabled in ObservabilityOptions. To control individual event types, pass an Analytics value directly:
The Analytics options are:
- taps: Emits a
clickspan for each detected tap. Defaults to.enabled. - trackEvents: Emits a
trackspan when a custom event is tracked withtrack(key:properties:metricValue:). Defaults to.enabled. - screenViews: Emits a
screen_viewspan when a screen appears. Defaults to.enabled. - appLifecycle: Emits
app_foregroundandapp_backgroundspans as the app moves between states. Defaults to.enabled. - appLaunch: Emits an
app_launchspan once per process launch, including anapp.startspan event with the cold or warm startup dimension. Defaults to.enabled.
App launch events
The iOS observability plugin records a single app_launch span once per process launch. The plugin captures process start timing as early as possible during launch using a startup constructor that runs before main, then emits the app_launch span after observability initializes. This means the recorded startup duration reflects actual launch time rather than SDK initialization time.
The app_launch span includes:
event.launch_type: Classifies the launch asinstall(first launch after install),update(first launch after a version update), orrelaunch(a subsequent launch of the same version). The plugin determines the launch type by comparing the current app version to the previously stored version.- Version attributes, including the current app version and, on an update, the previous version.
- An
app.startspan event with astart.typeattribute (coldorwarm) and, when available, astart.duration_msattribute. A warm start is detected when the operating system prewarms the app, using theActivePrewarmenvironment variable on iOS 15 and later.
To learn more about app launch attributes across SDKs, read App launch events.
Track screen views
The plugin emits a screen_view span when your app shows a screen. Each span uses the event.* attribute namespace, including event.name, event.screen_class, event.screen_id, event.previous_screen, and event.category. The plugin resolves event.previous_screen from a shared screen stack to ensure correctness whether the plugin captured the screen or your code recorded it manually.
Each recorded screen change also produces a session replay Navigate event to reflect navigation in the replay timeline.
Capture UIKit view controllers automatically
When instrumentation.screens is .enabled (the default), the plugin swizzles UIViewController and records a screen_view span each time a view controller appears. The plugin skips container and system controllers such as UINavigationController and UITabBarController.
To customize how the plugin reports a controller, conform it to LDScreenNameProviding:
Capture SwiftUI screens manually
The UIViewController swizzle does not observe pure SwiftUI navigation, such as NavigationStack destinations. You must record those screens manually.
Use the trackScreen modifier on the screen’s root view. Only one call per screen is required, because the plugin resolves event.previous_screen from the shared screen stack:
Track navigation stacks and modals
The trackScreen modifier records on .onAppear. SwiftUI does not re-run .onAppear when you pop back to a screen in a NavigationStack or when a sheet or fullScreenCover closes. Use the path-aware and presentation-aware modifiers to ensure that back navigation and modal returns are tracked correctly.
Apply trackScreenStack to the NavigationStack itself, passing the same path binding. The plugin records the top of the path, or the root name when the path is empty, on first appearance and on every push and pop. Return nil from destination to skip a screen that already records itself:
Apply trackScreenReturn to a presenting screen to record it again after a modal closes. Pass the flag, or combination of flags, that drives the presentation. The plugin records the screen on each transition from true to false:
Driving presentations from a single optional or enum route, such as sheet(item:), keeps isPresented to one expression. If you use multiple sheet(isPresented:) flags, combine them, as in isPresented: a || b || c.
Both trackScreenStack and trackScreenReturn require iOS 14, macOS 11, tvOS 14, or watchOS 7 and later.
Record a screen view directly
You can also call trackScreenView from anywhere after the SDK initializes. To learn more, read Recording product analytics events.
Manual trackScreenView calls work even when you disable automatic detection with instrumentation.screens. The analytics.screenViews option still gates the emitted screen_view span.
Manual instrumentation
To implement distributed tracing, all spans generated across different function calls and services for the same user request must share the same context.
Recording custom metrics
Use the metric methods on LDObserve.shared to record a Metric with a name and a value. Each method maps to a different OpenTelemetry instrument type:
Recording custom logs
Use LDObserve.shared.recordLog to emit a structured log. Pass attributes as a plain Swift dictionary through the properties parameter:
Recording custom errors
Use LDObserve.shared.recordError to report a caught error, with optional attributes for context:
Recording custom traces
Use LDObserve.shared.startSpan to create a span for tracing an operation. Always end the span when the operation completes:
Recording product analytics events
Use track to record a custom event as a product analytics span. Use trackScreenView to record a screen view:
Using span builder for advanced tracing
Use LDObserve.shared.spanBuilder when you need more control over a span than startSpan provides, such as setting the span kind or adding attributes before the span starts:
Using distributed tracing
To implement distributed tracing, all spans generated across different function calls and services for the same user request must share the same context.
While nested spans in the same scope automatically use the context of their parent span, Swift’s concurrency model (async, await, or Task) does not propagate the parent span context. Use the OpenTelemetry API to obtain and pass the parent span context explicitly to asynchronous methods:
Alternatively, you can store the current context and then later restore it in a different scope:
To propagate a span context to an entirely different service, use the OpenTelemetry W3CTraceContextPropagator to inject the context into outgoing HTTP headers. Services that receive the headers can then extract and use the context.
The above example adds header content similar to:
Services that receive the headers would use the extract method from W3CTraceContextPropagator to obtain fields from header and use them as the parent context for new spans.
Session management
The observability plugin automatically manages sessions and handles application lifecycle events. Sessions are automatically ended when:
- The application is backgrounded for longer than the configured
sessionBackgroundTimeout, which defaults to 15 minutes - The application is terminated
- A new session is explicitly started
Session timeout configuration
You can configure how long the plugin waits before ending a session when the app goes to the background:
Automatic instrumentation
The observability plugin automatically instruments your iOS application to collect:
- Application launch and lifecycle events: App launch, foreground, and background events, recorded as product analytics spans. To learn more, read Configure product analytics event collection.
- Session tracking: Automatic session start and end events with timing.
- Network requests: HTTP request/response data when enabled.
- Taps: A
clickspan for each tap interaction. - Screen views: A
screen_viewspan when aUIViewControllerappears, and a session replayNavigateevent on each screen change. To learn more, read Track screen views. - LaunchDarkly SDK events: Feature flag evaluations and SDK operations.
Session Replay
Session Replay is in Early Access
Session Replay is available in Early Access. APIs are subject to change until a 1.x version is released.
Session Replay captures user interactions and screen recordings to help you understand how users interact with your application. Session Replay works as an additional plugin that requires the observability plugin to be configured first.
Install the Session Replay plugin
First, add the Session Replay package as a dependency alongside the observability plugin:
Then, import the Session Replay plugin into your code:
Initialize Session Replay
To enable Session Replay, add the SessionReplay plugin to your SDK configuration alongside the Observability plugin. The Observability plugin must be added before the SessionReplay plugin:
Initialize the plugins after the SDK client
You can initialize the session replay plugin manually, after the SDK client is initialized.
This approach supports feature-flagged rollouts or dynamic initialization after end user consent. Set isEnabled to false in SessionReplayOptions, then call LDReplay.shared.start() when you’re ready to begin recording.
First, configure the plugin with isEnabled: false:
Then, start the session replay plugin when appropriate, such as after receiving end user consent or when a feature flag enables session replay.
This approach allows you to:
- Feature-flag the rollout of session replay to a subset of end users
- Wait for end user consent before starting data collection
- Dynamically enable session replay based on runtime conditions
- Maintain compliance with privacy regulations
Configure Session Replay privacy options
The Session Replay plugin provides privacy options to control what data is captured. Configure these options when initializing the plugin:
Privacy configuration options
The PrivacyOptions struct provides the following parameters:
- maskTextInputs: Mask all text input fields. Defaults to
true. - maskWebViews: Mask the contents of web views (
WKWebViewandUIWebView). When this setting is enabled, web views are rendered as blank rectangles in session replays. Defaults tofalse. - maskLabels: Mask all text labels. Defaults to
false. - maskImages: Mask all images. Defaults to
false. - maskUIViews: Array of
UIViewclasses to automatically mask in recordings. - ignoreUIViews: Array of
UIViewclasses to exclude from masking rules. - maskAccessibilityIdentifiers: Array of accessibility identifiers to mask. Use this to mask specific UI elements by their accessibility identifier.
- ignoreAccessibilityIdentifiers: Array of accessibility identifiers to exclude from masking rules.
- minimumAlpha: Minimum alpha value for view visibility in recordings. Views with alpha below this threshold are not captured. Defaults to
0.02.
Fine-grained masking control
You can override the default privacy settings on individual views. Use .ldMask() to mask a view, .ldUnmask() to exempt one from masking, and .ldPrivate(isEnabled:) to mask a view conditionally. These give you precise control over what session replay captures.
SwiftUI view masking
Use view modifiers to control masking for SwiftUI views:
UIKit view masking
Use the .ldMask(), .ldUnmask(), and .ldPrivate(isEnabled:) methods on UIView instances:
Masking precedence
When the SDK decides whether to mask a view, it evaluates the following rules in order and stops at the first rule that applies:
- Explicit masking: If the view or any of its parent views is explicitly masked with
.ldMask()or a matchingmaskAccessibilityIdentifiersentry, the SDK masks the view. This overrides all other rules. - Explicit unmasking: If the view or any of its parent views is explicitly unmasked with
.ldUnmask(), the SDK does not mask the view. - Global configuration: If a global privacy option such as
maskTextInputsormaskImagesapplies to the view, the SDK follows that option.
If rules conflict at the same level, masking wins over unmasking.
Explore supported features
The observability plugin supports the following features. After the SDK and plugins are initialized, you can access these from within your application:
- Configuration for client-side observability
- Configuration for session replay
- Errors
- Logs
- Metrics
- Symbolication
- Tracing
Review observability data in LaunchDarkly
After you initialize the SDK and observability plugin, your application automatically starts sending observability data back to LaunchDarkly in the form of custom events and OpenTelemetry data. You can review this information in the LaunchDarkly user interface. To learn how, read Observability.
The observability data collected includes:
- Error monitoring: Unhandled exceptions, crashes, and manually recorded errors with stack traces
- Logs: Application logs with configurable severity levels and custom attributes
- Traces: Distributed tracing data including span timing, nested operations, and custom instrumentation
- Metrics: Performance metrics, custom counters, histograms, and gauge measurements
- Session data: User session information including lifecycle events and timing
Specifically, the observability data includes events that LaunchDarkly uses to automatically create the following metrics:
- User error rate and crash frequency
- Application performance metrics such as launch time and session duration
- Feature flag evaluation context and timing
- Custom business metrics recorded through the SDK
To learn more about autogenerated metrics, read Observability autogenerated metrics.