launchdarkly_flutter_observability package provides error monitoring, logging, tracing, and session replay through a single public facade named LDObserve.
SDK quick linksLaunchDarkly SDKs are open source. In addition to this reference guide, we provide source, API reference documentation, and a sample application:
| Resource | Location |
|---|---|
| GitHub repository | @launchdarkly/flutter observability |
| Sample application | Flutter example app |
Prerequisites and dependencies
This reference guide assumes you are familiar with the LaunchDarkly Flutter SDK. The observability plugin requires:- The LaunchDarkly Flutter SDK version 4.18.0 or later
- Flutter 3.27 or later
- An iOS deployment target of 15.0 or later
- Android SDK version 24 or later (Android 7.0, Nougat)
Get started
Follow these steps to get started:- Install the package
- Initialize observability
- Configure plugin options
- Configure session replay
- Record screen views
- Record taps
- Manually instrument your app
- Explore supported features
- Review observability data in LaunchDarkly
Install the package
Add both the LaunchDarkly Flutter SDK and the observability package to yourpubspec.yaml:
ios/Podfile:
ios/ directory:
Initialize observability
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 Flutter SDK reference guide. There are two initialization variants. UseLDObserve.init if you are using the LaunchDarkly client, or LDObserve.initStandalone to initialize without a client.
Both variants return a Future<bool> that completes with true when observability is ready. Awaiting the future is optional, but the plugin drops anything that you record before it completes, except for the most recent screen view. The plugin replays it after startup finishes. Await the future before you record anything that must not be lost.
The future never completes with an error. It completes with false if startup fails, or if you already called LDObserve.shutdown(). If startup fails, the plugin logs the error, and you can call init again to retry the startup. Only the first successful call takes effect. The plugin logs and ignores any later call, including its options, and reports only the first call’s outcome.
Initialize with a LaunchDarkly client
Pass yourLDClient to LDObserve.init. This registers the observability plugin on the client so feature flag evaluations are correlated with your telemetry:
Initialize standalone
To initialize without creating a LaunchDarkly client, pass your mobile key directly toLDObserve.initStandalone:
initStandalone has no LaunchDarkly client to register a hook on, it does not record a span for each feature flag evaluation. Every other kind of telemetry works in the same way it does with LDObserve.init.
Configure plugin options
Pass anObservabilityOptions object to LDObserve.init or LDObserve.initStandalone to configure observability behavior:
ObservabilityOptions configuration options are available on all platforms:
- isEnabled: Enables or disables observability telemetry. Defaults to
true. Whenfalse, the plugin records no spans, logs, errors, flag evaluation spans, lifecycle spans, ordebugPrintoutput, and exports nothing on web. Session replay is controlled separately withSessionReplayOptions.isEnabled. While session replay is on, screen views, taps, and track events still reach the replay timeline. - serviceName: The service name for telemetry. Defaults to
"observability-flutter", which names the plugin rather than your app. Set it to identify your app. - serviceVersion: The service version, commonly a Git SHA or semantic version string. This option is optional. If you omit it, Android and iOS report your app’s own version, which Flutter sets from the
versionin yourpubspec.yaml, and web omitsservice.version. - instrumentation: An
InstrumentationOptionsobject that controls automatic instrumentation. To learn more, read Instrumentation options. - otlpEndpoint: The OpenTelemetry Protocol (OTLP) endpoint for reporting OpenTelemetry data. Defaults to
https://otel.observability.app.launchdarkly.com:4318. You do not need to change this for most configurations. - backendUrl: The LaunchDarkly back-end URL. Defaults to
https://pub.observability.app.launchdarkly.com. You do not need to change this for most configurations. - contextFriendlyName: A display name to identify the user’s session in the observability UI.
- attributes: A map of additional OpenTelemetry resource attributes to attach to every signal the plugin exports. For example,
{'deployment.environment': 'staging'}. If one of your attributes uses the same key as an attribute the plugin sets, such as aservice.*key or the project identifier, the plugin’s value wins. - analytics: An
AnalyticsOptionsobject that controls telemetry for product analytics events. UseAnalyticsOptions.enabledto enable all types orAnalyticsOptions.disabledto disable all:- taps: Emits a
clickspan for each user tap. Defaults totrue. Setting this tofalsealso stops tap detection, rather than detecting taps without publishing them. To learn more, read Record taps. - views: Emits a
screen_viewspan for each screen view. Defaults totrue. To learn more, read Record screen views. - trackEvents: Emits a
trackspan when a custom event is tracked withtrack(). Defaults totrue. - appLifecycle: Emits app lifecycle spans. Defaults to
true. On every platform, including web, this option gates the Dartdevice.app.lifecyclespan that the plugin emits on each FlutterAppLifecycleStatechange. On Android and iOS, it also gates the nativeapp_foregroundandapp_backgroundspans. - appLaunch (Android and iOS): Emits an
app_launchspan once per process launch. The span carries the launch type, which isinstall,update, orrelaunch, along with version information and anapp.startspan event that records the cold or warm startup dimension. Defaults totrue.InstrumentationOptions.launchTimesseparately controls launch time measurement. - customClickTargetResolver: A function that names your own widget types as tap targets. To learn more, read Name your own widget types. To learn more, read Product analytics events.
- taps: Emits a
ObservabilityOptions configuration options are available only on Android and iOS:
- customHeaders: Extra HTTP headers added to OTLP exports, for example for proxies or authentication. Defaults to
{}. - sessionBackgroundTimeout: How long the app can stay in the background before the session ends. Defaults to 15 minutes.
- logsApiLevel: The minimum severity of logs forwarded to the logs pipeline. Use
ObservabilityLogLevel.noneto disable logs. Defaults toObservabilityLogLevel.info. - traces: A
TracesOptionsobject that controls automatic trace generation. TogglesincludeErrorsandincludeSpans. Both default totrue. - metricsEnabled: Whether metrics are exported. Defaults to
true.
Instrumentation options
TheInstrumentationOptions class controls which automatic instrumentation features are active. Pass it to the instrumentation parameter of ObservabilityOptions.
- launchTimes: When
true, measures and reports application launch time. Defaults totrue. - debugPrint: Controls whether
debugPrintcalls are automatically captured as log events:DebugPrintSetting.releaseOnly()(the default) capturesdebugPrintcalls only in release builds.DebugPrintSetting.always()capturesdebugPrintcalls in all build configurations. When enabled,debugPrintoutput does not appear in the Flutter console.DebugPrintSetting.disabled()does not instrumentdebugPrint.
InstrumentationOptions configuration option is available only on Android and iOS:
- crashReporting: When
true, reports uncaught exceptions as errors. Defaults totrue.
The plugin does not instrument HTTP requests automaticallyFlutter’s HTTP clients go through
dart:io, which the native network instrumentation in the Android and iOS observability SDKs cannot observe. To trace an HTTP request, wrap it in LDObserve.withSpan. To learn more, read Record scoped spans.Intercept print statements
To capture the output fromprint statements, pass LDObserve.zoneSpecification() to runZonedGuarded:
Map contexts to friendly names
UsecontextFriendlyName to set a human-readable display name for the user’s session when displayed in the observability User Interface (UI):
Configure product analytics event collection
The observability SDK for Flutter can record the following product analytics events as OpenTelemetry spans:- Track events (manual, all platforms): A
trackspan recorded when your code callsLDObserve.track(). ThetrackEventsflag inAnalyticsOptionscontrols whether the span is emitted. To learn more, read Recording product analytics events. - Taps (automatic, all platforms): A
clickspan for each user tap, with the widget type, identifier, visible label, widget ancestry path, and coordinates. Enabled by default. Tap capture requires theSessionReplayCapturewidget. To learn more, read Record taps. - Screen views (automatic or manual, all platforms): A
screen_viewspan when your app shows a screen, with the screen name and optional details such as the screen class, screen identifier, and category. Enabled by default. Screen views are reported from your Dart code, either by theLDNavigatorObserveror by a call toLDObserve.trackScreenView. To learn more, read Record screen views. - App lifecycle (automatic, all platforms): A
device.app.lifecyclespan on each FlutterAppLifecycleStatechange. On Android and iOS, the plugin also emits a nativeapp_foregroundorapp_backgroundspan as the app moves between the foreground and background states. Enabled by default. - App launches (automatic, Android and iOS): An
app_launchspan once per process launch. The span carries the launch type, which isinstall,update, orrelaunch, along with version information and anapp.startspan event that records the cold or warm startup dimension. Enabled by default. To learn more, read App launch events.
analytics to AnalyticsOptions.enabled in ObservabilityOptions:
AnalyticsOptions instead:
Default values for product analyticsTrack event, tap, screen view, app lifecycle, and app launch collection are all enabled by default. Use
AnalyticsOptions.disabled to disable all product analytics spans at once.taps and views options behave differently on mobile than they do on web:
- taps: Gates the Dart-side tap detection as well as the
clickspan. Setting it tofalsestops the plugin from resolving tapped widgets at all. On Android and iOS, the session replay Click timeline event is recorded regardless of this setting. - views: Gates the
screen_viewspan only. On Android and iOS, the session replay Navigate timeline event is recorded regardless of this setting. - appLifecycle: Gates the Dart
device.app.lifecyclespan on every platform. On Android and iOS, it also gates the nativeapp_foregroundandapp_backgroundspans.
AnalyticsOptions also accepts a customClickTargetResolver, which names your own widget types as tap targets. To learn more, read Name your own widget types.
Configure session replay
Session replay captures screen recordings of user actions to help you understand how users interact with your application. It is included in thelaunchdarkly_flutter_observability package and uses native iOS and Android libraries to capture and upload recordings.
Session replay for Flutter is supported only on iOS and Android. It is not supported on web.
Initialize session replay
To enable session replay, pass aSessionReplayOptions object to the replay parameter of LDObserve.init or LDObserve.initStandalone, and wrap your app in SessionReplayCapture:
SessionReplayCapture widget
Wrap your top-level widget inSessionReplayCapture to allow the native session replay library to capture screen content. Because session replay is not supported on web, the widget records nothing there, but it still hosts tap capture on every platform. Wrapping your app with it is safe and useful on every platform:
MaterialApp. Dialogs, bottom sheets, and other routes are children of the app’s Navigator, so a wrapper further down the tree excludes taps on anything your app pushes above it. To learn more, read Record taps.
Session replay configuration options
Pass aSessionReplayOptions object to LDObserve.init or LDObserve.initStandalone to control session replay behavior:
replay parameter, session replay does not start. The isEnabled default applies only to the SessionReplayOptions object you pass in.
These SessionReplayOptions configuration options are available on all platforms:
- isEnabled: Controls whether session recording starts on Android and iOS. Defaults to
true. This option has no effect on web, where session replay is not supported. - privacy: A
PrivacyOptionsobject that controls which UI elements are masked. To learn more, read Privacy options. - serviceName: The service name reported for session replay telemetry. Defaults to
"sessionreplay-flutter".
SessionReplayOptions configuration options are available only on Android and iOS:
- sampleRate: Probability from
0.0to1.0that session replay starts when enabled. Defaults to1.0. - frameRate: Target capture rate in frames per second. Defaults to
1.0. - scale: The resolution multiplier for captured frames, where
1.0is 1x (160 DPI) and2.0is 2x. Higher values capture more detail but produce larger frames. Anullvalue is treated as1.0. Defaults to1.0. - imageQuality: The JPEG encoding quality of exported frames, from
0.0(lowest quality, smallest payload) to1.0(highest quality, largest payload). Values outside that range are clamped. Defaults to0.3.
Privacy options
UsePrivacyOptions to control which elements are masked in session replay recordings. By default, text inputs are masked to protect user data.
- maskTextInputs: Masks all text input fields. Defaults to
true. - maskWebViews: Masks the contents of web views. When enabled, web views appear as blank rectangles in recordings. Defaults to
false. - maskLabels: Masks all text labels. Defaults to
false. - maskImages: Masks all images. Defaults to
false. - minimumAlpha: The opacity threshold, from
0.0to1.0, below which the plugin treats a widget as invisible and skips it during capture and masking. Raise it to ignore nearly transparent UI. Defaults to0.02. - maskClickText: Drops the visible label from click events. Taps report the widget type and identifier but no text. Defaults to
false. This option is independent ofmaskLabels, which controls whether the plugin paints over text in captured frames. To learn more, read Record taps.
Per-widget masking
In addition to screen-widePrivacyOptions, you can redact individual widgets using LDMask, LDIgnore, and LDUnmask.
Use LDMask to redact a widget’s subtree in all captured frames:
LDIgnore to exclude a subtree from session replay entirely. In Flutter, LDIgnore behaves like LDMask and paints over the region in every captured frame, so its contents never appear in a recording:
LDUnmask to exempt a subtree from global masking rules such as maskTextInputs. For example, to reveal one non-sensitive field on a page where every input is masked:
LDUnmask only overrides global masking. It does not override an explicit LDMask or LDIgnore. An LDUnmask nested inside either one stays masked, because an explicit per-widget mask always takes precedence.
LDMask, LDIgnore, and LDUnmask are active on iOS and Android. On web, where session replay is not supported, they render their child unchanged.
Mask by widget type or key
When wrapping widgets is not convenient, name them once inPrivacyOptions by their Type or Key. LaunchDarkly resolves these rules on the Flutter side and does not send them to the native SDKs:
- maskWidgetTypes: A set of widget
Types to mask wherever they appear. Defaults to an empty set. - maskWidgetKeys: A set of widget
Keys to mask wherever they appear. Defaults to an empty set. - unmaskWidgetTypes: A set of widget
Types to reveal from global masking. Defaults to an empty set. - unmaskWidgetKeys: A set of widget
Keys to reveal from global masking. Defaults to an empty set. - ignoreWidgetTypes: A set of widget
Types to ignore. Defaults to an empty set. - ignoreWidgetKeys: A set of widget
Keys to ignore. Defaults to an empty set.
Record screen views
Flutter renders your entire app into a single native view, so the native observability SDKs never detect your Flutter route changes. To record screen views, report route changes from your Dart code. Each screen view emits ascreen_view span. On Android and iOS, it also adds a Navigate event to the session replay timeline.
Record screen views automatically
Add anLDNavigatorObserver to the navigatorObservers list on your top-level navigator. Every route change then becomes a screen view:
route.settings.name and skips routes that do not have one. An app that pushes a bare MaterialPageRoute records nothing and reports no error. To avoid this, name your routes where you push them:
showDialog and showModalBottomSheet push without settings from appearing as screens.
To record those routes anyway, or to derive screen names another way, pass a screenNameExtractor. Returning null from the extractor skips the route, so the extractor also works as a filter for routes you do not want to record:
Report route patterns instead of URLs
Routers that navigate by URL, including go_router, GetX, Beamer, and auto_route, put the concrete path inroute.settings.name. Without route patterns, '/orders/42' becomes its own screen, one screen fragments into one screen per order, and an order identifier ends up in a name that appears in the LaunchDarkly UI.
The observer also drops the query string and fragment from every screen name. This means '/reset?token=abc123' and '/search?q=running+shoes' are reported as /reset and /search. A query string holds values rather than structure, and a screen name identifies a screen. Because names that are not paths keep their punctuation, a confirmation route named 'Delete this?' is reported as written.
Path parameters are the one part of a route name that the plugin cannot resolve on its own. Only your app knows which segments are identifiers. List the patterns your app registers, and LDRoutePatterns.extractor collapses concrete paths back onto them:
/orders, /orders/:id, and /orders/:id/receipt, no matter which order identifiers are involved.
Patterns use the same syntax those routers use:
- A
:namesegment matches exactly one path segment. - A trailing
*matches the rest of the path.
'/orders/new' before '/orders/:id'.
Because a route that matches no pattern is reported by its path, any screen you forget to list still appears. To treat your pattern list as an allow list and record only those patterns you name, pass skipUnmatched: true.
Navigation an observer cannot see
EachLDNavigatorObserver instance observes a single navigator, and Flutter asserts if you share one instance between navigators. The following setups need additional configuration:
- Nested navigators: A tab shell, or a
Navigatorinside a page, reports only its own routes. Create a separate observer instance for each navigator. MaterialApp.router: Routers such as go_router, auto_route, and Beamer do not acceptnavigatorObservers. Pass the observer to the router’s own observer list instead, such asGoRouter(observers: [LDNavigatorObserver()]).GetMaterialApp: GetX merges the observers you pass with its own, sonavigatorObservers: [LDNavigatorObserver()]works the same way it does onMaterialApp.GetMaterialApp.routeris the exception. It acceptsnavigatorObserversand then builds its delegate without them, so pass them asrouterDelegate: GetDelegate(navigatorObservers: [LDNavigatorObserver()])instead.- Navigation that leaves the route stack unchanged: Switching tabs in an
IndexedStack, or paging aPageView, is invisible to any observer. Record these screen views manually.
Record screen views manually
To record a screen view yourself, or to add detail that an observer cannot supply, callLDObserve.trackScreenView:
screenClass, screenId, and category as the event.screen_class, event.screen_id, and event.category span attributes, and attaches any properties you pass as additional attributes.
Record taps
The plugin captures taps automatically and records each one as aclick span. Every tap that resolves to a recognized widget describes that widget by type, identifier, visible label, ancestry path, and coordinates. On Android and iOS, the same tap also adds a Click event to the session replay timeline. This enables you to jump to the moment a user pressed a widget.
Tap capture requires you to wrap your widget tree in SessionReplayCapture, which hosts the tap detector on every platform, including web. To learn more, read SessionReplayCapture widget.
The plugin resolves the tapped widget in Dart, because Flutter renders its entire interface into one native view. A native hit test names that view, FlutterSurfaceView, for every tap in your app regardless of which widget the user pressed.
Tap event attributes
Eachclick span carries the following attributes:
| Attribute | Description |
|---|---|
event.tag | The widget type, such as ElevatedButton. |
event.id | A stable identifier for the widget. The plugin uses the first value it finds, in this order: the id of an enclosing LDClick, an id from your customClickTargetResolver, a Semantics.identifier, or a ValueKey. This attribute is optional. A widget with none of these is still reported, grouped by type and ancestry path. |
event.text | The visible label: a button’s own text, or otherwise a semantic label, icon label, or tooltip. The plugin does not harvest a container’s inner text, so a tapped row reports ListTile rather than whichever word sat under the user’s finger. A Radio with no label falls back to its value. |
event.xpath | The widget ancestry, such as Scaffold/Column/ProductRow/IconButton#cart.add. The plugin leaves out framework plumbing, including theme and media query providers, builders, focus and semantics wrappers, and single-child layout and painting boxes, and keeps only the innermost ten segments. |
event.x, event.y | The tap coordinates. Automatic capture reports the units native taps use on that platform, which are physical pixels on Android and logical pixels on iOS. This means a Flutter tap lands on the session replay timeline next to a native one. LDObserve.trackClick takes x and y as double logical pixels, the units of a gesture’s globalPosition, and converts them to those same platform units. Manual and automatic taps therefore share one coordinate space. |
- Material and Cupertino buttons, including
IconButtonandFloatingActionButton - Selection controls, including
Switch,Checkbox,Radio, andSlider - Chips, tabs, and menus, including
PopupMenuButtonandDropdownButton - Navigation bars
ListTile,InkWell, andGestureDetector
event.xpath segments for widget types the plugin does not recognize come from the Dart runtime type, which release builds compiled with --obfuscate mangle. The event.tag and event.id attributes stay readable in obfuscated builds, so you can group your product analytics charts on those attributes.
Name a widget with LDClick
To give a specific widget a stable identifier, wrap it inLDClick. Because the widget renders its child unchanged and emits nothing itself, wrapping a button cannot double count a tap:
id of the nearest enclosing LDClick, so you can wrap a composite control to name the entire control. Use LDClick when a widget has no Key or Semantics.identifier, or when the automatic name is too generic to group on.
Name your own widget types
A design system button often looks like an anonymous composition of Material widgets. To name every instance of one of your own widget types at once, register acustomClickTargetResolver in AnalyticsOptions instead of tagging each call site:
LDClickTargetInfo for the types you want to name, and null for everything else so the built-in rules apply. LDClickTargetInfo accepts the following parameters:
- tag: The widget type name reported as
event.tag. Required. - id: A stable identifier for the instance, reported as
event.id. - text: The visible label, reported as
event.text. If you omit it, the plugin falls back to its usual text extraction. - preferInnerTarget: When
true, a more specific target nested inside this widget is reported instead. Set this for containers that only make a region tappable, such as a card or a row, to ensure that the plugin reports a button inside the containers. Defaults tofalse.
tag rather than runtimeType.toString(). Release builds compiled with --obfuscate mangle runtime type names, which would group the same widget differently in every build.
The resolver runs for every widget above the tap, so keep it inexpensive and free of side effects. The plugin catches and logs an exception from your resolver and then continues with the built-in rules.
Record taps manually
For an interaction that automatic capture cannot observe, such as a shake, a hardware button, or a custom gesture recognizer, callLDObserve.trackClick yourself. Pass x and y as double logical pixels, the same units a Flutter Offset uses. The plugin converts them to the units automatic capture reports on the current platform:
LDObserve.trackClick from an onPressed handler that automatic capture already observes, because that counts the tap twice. To give an automatically captured widget a stable name, wrap it in LDClick instead.
Tap capture limitations
Tap capture has the following limitations:- Only taps count as clicks. The plugin does not report a press that moves further than
kTouchSlop, such as a scroll or a drag, a press that outlasts the long press timeout, or any multi-touch gesture. The native SDKs apply the same rule, which keeps Flutter and native clicks comparable. - Embedded platform views resolve to their host widget. A tap in a
WebViewor a native map reports the Flutter widget hosting it, such asWebViewWidget. The plugin does not describe what the user pressed inside the embedded view. - Pointer-blocking overlays are honored. An
IgnorePointeris transparent to the plugin, because the tap passed through it. Because anAbsorbPointer, such as a loading overlay laid over aStack, consumes the tap, the plugin reports neither its children nor the controls painted behind it. This matches what Flutter delivered to your app. - Tap labels follow your masking rules. The plugin never reports text inside an
LDMaskorLDIgnoresubtree, and never reads the contents of an editable field. SettingmaskClickTextinPrivacyOptionsturns off tap labels entirely while still recording the taps. To learn more, read Privacy options.
Manual instrumentation
After initializing the observability plugin, useLDObserve to manually instrument your Flutter application with custom logs, errors, traces, and product analytics events.
Recording custom logs
UseLDObserve.recordLog to emit a structured log. severity is a LogSeverity value: trace, debug, info, warn, error, or fatal. It defaults to LogSeverity.info. properties is a plain Dart map with no LaunchDarkly or OpenTelemetry types required:
LogSeverity value carries the OpenTelemetry severity number the plugin exports it with. LogSeverity is distinct from ObservabilityLogLevel, which sets the minimum severity the native SDKs export. To learn more, read Configure plugin options.
If you record a log while a span is active, the plugin associates the log with that span through the OpenTelemetry context:
Record errors
UseLDObserve.recordException to capture an error. Because the stack trace in Dart is independent of the exception, capture both together:
properties map.
Recording custom traces
UseLDObserve.startSpan to create a span for tracing an operation. Spans nest automatically under the currently active span. Always end spans when the operation completes:
kind parameter to startSpan. SpanKind supports internal, which is the default, along with client, server, producer, and consumer.
Each span supports these methods:
- setAttribute(name, value): Sets a single attribute on the span.
- setAttributes(map): Sets multiple attributes on the span.
- addEvent(name, ): Records a named event on the span.
- setStatus(SpanStatusCode): Sets the span status to
ok,error, orunset. - recordException(exception, ): Records an exception on the span.
- end(): Ends the span.
end() again on a span that already ended does nothing.
To record spans independently instead of nesting them, end each span before you start the next:
Record scoped spans
UseLDObserve.withSpan to run a function inside a new span that the plugin ends for you, either when the function returns or when its Future completes. withSpan returns whatever the function returns:
await boundaries, any span you start inside the function is a child of it. If the function throws an error or its future fails, the plugin records the error on the span, sets the span status to SpanStatusCode.error, and rethrows the error unchanged.
We recommend withSpan for asynchronous work. A span from startSpan stays current for every piece of code in the zone until you end it, including unrelated work that runs during an await.
Because the plugin does not instrument HTTP requests automatically, wrap a request in withSpan to trace it:
Attribute and property values
Attributes and properties are plain Dart values. No LaunchDarkly or OpenTelemetry types are required. A value can be aString, int, double, bool, or a homogeneous list of any of those types. The SDK ignores values it cannot represent as an attribute, such as nested maps or mixed-type lists.
The recordLog, recordException, startSpan, withSpan, track, trackScreenView, and trackClick methods all accept a properties map of these same plain values.
Recording product analytics events
UseLDObserve.track to record a custom event as a product analytics span:
LDObserve also records screen views and taps manually. To learn more, read Record screen views manually and Record taps manually.
Shut down observability
CallLDObserve.shutdown() to shut down observability and session replay for the rest of the process. The plugin flushes buffered spans and stops native session replay. It also removes the Dart instrumentation for lifecycle, debugPrint, and tap capture, and turns every recording method into a no-op.
LDObserve.init or LDObserve.initStandalone afterward does nothing.
shutdown returns a Future<void> that completes after native session replay stops. Awaiting it is optional. The future never completes with an error, and repeated calls return the same future.
Because the native observability SDK on Android and iOS has no teardown, its automatic instrumentation, including crash reporting, launch times, and native lifecycle spans, keeps running until the process exits.
Identify contexts
To tie observability data to the correct context, use the LaunchDarkly client to identify or switch contexts:LDObserve method. The observability plugin hooks into the LaunchDarkly client and, on Android and iOS, forwards each completed identify to the native observability SDK and to session replay. This attributes subsequent LDObserve.track events to the active context and records the context on the active session replay recording.
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
- Symbolication
- Tracing