> ## Documentation Index
> Fetch the complete documentation index at: https://launchdarkly-preview.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Android SDK observability reference

> This topic documents how to get started with the LaunchDarkly observability plugin for the Android SDK.

> For the complete documentation index, see [llms.txt](/llms.txt). For the full documentation snapshot, see [llms-full.txt](/llms-full.txt).

<Note title="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.
</Note>

## Overview

This topic documents how to get started with the LaunchDarkly observability plugin for the Android SDK.

The Android SDK supports the **observability plugin** for error monitoring, logging, tracing, and **session replay**.

<Note title="SDK quick links">
  LaunchDarkly's SDKs are open source. In addition to this reference guide, we provide source, API reference documentation, and a sample application:
</Note>

| Resource | Location |
| - | - |
| SDK API documentation | [Observability plugin API docs](https://launchdarkly.github.io/observability-sdk/sdk/@launchdarkly/observability-android/) |
| GitHub repository | [@launchdarkly/observability-android](https://github.com/launchdarkly/observability-sdk/tree/main/sdk/%40launchdarkly/observability-android) |
| Published module | [Maven](https://mvnrepository.com/artifact/com.launchdarkly/launchdarkly-observability-android) |

## Prerequisites and dependencies

This reference guide assumes that you are somewhat familiar with the LaunchDarkly [Android SDK](/sdk/client-side/android).

The observability plugin is compatible with the [Android SDK](/sdk/client-side/android), version 5.9.0 and later.

The LaunchDarkly Android SDK is compatible with Android SDK versions 21 and higher (Android 5.0, Lollipop).

## Get started

Follow these steps to get started:

* [Install the plugin](#install-the-plugin)
* [Initialize the Android SDK client](#initialize-the-client)
* [Configure the plugin options](#configure-the-plugin-options)
* [Configure additional instrumentations](#configure-additional-instrumentations)
* [Configure session replay](#configure-session-replay)
* [Explore supported features](#explore-supported-features)
* [Review observability data in LaunchDarkly](#review-observability-data-in-launchdarkly)

## Install the plugin

LaunchDarkly uses a plugin to the Android SDK to provide observability.

The first step is to make both the SDK and the observability plugin available as dependencies.

Here's how:

<CodeGroup>
  ```java title="Gradle Groovy" theme={null}
      implementation 'com.launchdarkly:launchdarkly-android-client-sdk:5.+'
      implementation 'com.launchdarkly:launchdarkly-observability-android:0.21.0'
  ```

  ```kotlin title="Gradle Kotlin" theme={null}
      implementation("com.launchdarkly:launchdarkly-android-client-sdk:5.+")
      implementation("com.launchdarkly:launchdarkly-observability-android:0.21.0")
  ```
</CodeGroup>

Then, import the plugin into your code:

<CodeGroup>
  ```java title="Import for Java" theme={null}
      import com.launchdarkly.sdk.*;
      import com.launchdarkly.sdk.android.*;
      import com.launchdarkly.observability.plugin.Observability;
      import com.launchdarkly.sdk.android.integrations.Plugin;
  ```

  ```kotlin title="Import for Kotlin" theme={null}
      import com.launchdarkly.sdk.*
      import com.launchdarkly.sdk.android.*
      import com.launchdarkly.observability.plugin.Observability
      import com.launchdarkly.sdk.android.integrations.Plugin
  ```
</CodeGroup>

## Initialize the client

Next, initialize the SDK and the plugin.

To initialize, you need your LaunchDarkly environment's mobile key and the context for which you want to evaluate flags. This authorizes your application to connect to a particular environment within LaunchDarkly. To learn more, read [Initialize the client](/sdk/client-side/android#initialize-the-client) in the Android SDK reference guide.

<Warning title="Android observability SDK credentials">
  The Android observability SDK uses a mobile key. Keys are specific to each project and environment. They are available from **Project settings**, on the **Environments** list. To learn more about key types, read [Keys](/sdk/concepts/client-side-server-side#keys).

  Mobile keys are not secret and you can expose them in your client-side code without risk. However, never embed a server-side SDK key into a client-side application.
</Warning>

Here's how to initialize the SDK and plugin:

<CodeGroup>
  ```java title="Android SDK v5.x (Java)" theme={null}
      String mobileKey = "example-mobile-key";

      LDConfig ldConfig = new LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(Components.plugins().setPlugins(
            Collections.singletonList<Plugin>(Observability(this.getApplication(), mobileKey))
          ))
          // other options
          .build();

      // You'll need this context later, but you can ignore it for now.
      LDContext context = LDContext.create("example-context-key");

      LDClient client = LDClient.init(this.getApplication(), ldConfig, context, 0);
  ```

  ```kotlin title="Android SDK v5.x (Kotlin)" theme={null}
      val mobileKey = "example-mobile-key"

      val ldConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(Components.plugins().setPlugins(
            listOf(Observability(this@BaseApplication, mobileKey))
          ))
          // other options
          .build()

      // You'll need this context later, but you can ignore it for now.
      val context = LDContext.create("example-context-key")

      val client: LDClient = LDClient.init(this@BaseApplication, ldConfig, context, 0)
  ```
</CodeGroup>

## 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:

<CodeGroup>
  ```java title="Plugin options, Android SDK v5.9+" theme={null}
      String mobileKey = "example-mobile-key";

      LDConfig ldConfig = new LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(
            Components.plugins().setPlugins(
              Collections.singletonList<Plugin>(
                Observability(
                  this.getApplication(),
                  mobileKey,
                  ObservabilityOptions(
                    resourceAttributes = Attributes.of(
                      AttributeKey.stringKey("serviceName"), "example-service"
                    )
                  )
                )
              )
            )
          )
          .build();
  ```
</CodeGroup>

For more information on plugin options, read [Configuration for client-side observability](/sdk/features/observability-config-client-side).

### Advanced configuration options

You can customize the observability plugin with additional options:

<CodeGroup>
  ```kotlin title="Advanced options example" theme={null}
      val mobileKey = "example-mobile-key"

      val ldConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(
            Components.plugins().setPlugins(
              listOf(
                Observability(
                  this@BaseApplication,
                  mobileKey,
                  ObservabilityOptions(
                    serviceName = "my-android-app",
                    serviceVersion = "1.0.0",
                    debug = true,
                    logsApiLevel = ObservabilityOptions.LogLevel.WARN,
                    tracesApi = ObservabilityOptions.TracesApi(includeErrors = true, includeSpans = false),
                    metricsApi = ObservabilityOptions.MetricsApi.disabled(),
                    instrumentations = ObservabilityOptions.Instrumentations(
                      crashReporting = false,
                      activityLifecycle = true,
                      launchTime = true
                    ),
                    resourceAttributes = Attributes.of(
                      AttributeKey.stringKey("environment"), "production",
                      AttributeKey.stringKey("team"), "mobile"
                    ),
                    customHeaders = mapOf(
                      "X-Custom-Header" to "custom-value"
                    )
                  )
                )
              )
            )
          )
          .build()
  ```
</CodeGroup>

The available `ObservabilityOptions` configuration options are:

* **logsApiLevel**: Minimum log severity to export. Defaults to `INFO`. Set to `ObservabilityOptions.LogLevel.NONE` to disable log exporting.
* **tracesApi**: Controls trace recording. Defaults to enabled. Use `ObservabilityOptions.TracesApi.disabled()` to disable all tracing, or set `includeErrors`/`includeSpans` individually.
* **metricsApi**: Controls metric export. Defaults to enabled. Use `ObservabilityOptions.MetricsApi.disabled()` to disable metrics.
* **instrumentations**: Enables or disables specific automatic instrumentations:
  * `crashReporting`: If `true`, automatically reports uncaught exceptions as errors. Defaults to `true`.
  * `activityLifecycle`: If `true`, automatically starts spans for Android Activity lifecycle events. Defaults to `true`.
  * `launchTime`: If `true`, automatically measures and reports application startup time as metrics. Defaults to `false`.
* **serviceName**: The service name for the application. Defaults to "observability-android".
* **serviceVersion**: The version of the service. Defaults to the SDK version.
* **debug**: Enables verbose internal logging and debug functionality. Defaults to `false`.
* **resourceAttributes**: Additional resource attributes to include in telemetry data.
* **customHeaders**: Custom headers to include with OTLP exports.

## Configure additional instrumentations

To enable HTTP request instrumentation and user interaction instrumentation, add the following plugin and dependencies to your top level application's Gradle file.

<CodeGroup>
  ```java title="Gradle Groovy" theme={null}
      plugins {
          id 'net.bytebuddy.byte-buddy-gradle-plugin' version '1.+'
      }

      dependencies {
          // Android HTTP Url instrumentation
          implementation 'io.opentelemetry.android.instrumentation:httpurlconnection-library:0.11.0-alpha'
          byteBuddy 'io.opentelemetry.android.instrumentation:httpurlconnection-agent:0.11.0-alpha'

          // OkHTTP instrumentation
          implementation 'io.opentelemetry.android.instrumentation:okhttp3-library:0.11.0-alpha'
          byteBuddy 'io.opentelemetry.android.instrumentation:okhttp3-agent:0.11.0-alpha'
      }
  ```

  ```kotlin title="Gradle Kotlin" theme={null}
      plugins {
          id("net.bytebuddy.byte-buddy-gradle-plugin") version "1.+"
      }

      dependencies {
          // Android HTTP Url instrumentation
          implementation("io.opentelemetry.android.instrumentation:httpurlconnection-library:0.11.0-alpha")
          byteBuddy("io.opentelemetry.android.instrumentation:httpurlconnection-agent:0.11.0-alpha")

          // OkHTTP instrumentation
          implementation("io.opentelemetry.android.instrumentation:okhttp3-library:0.11.0-alpha")
          byteBuddy("io.opentelemetry.android.instrumentation:okhttp3-agent:0.11.0-alpha")
      }
  ```
</CodeGroup>

## Configure session replay

The Android SDK supports session replay, which captures snapshots of your app's UI at regular intervals. This allows you to visually review user sessions in LaunchDarkly to better understand user behavior and diagnose issues.

To enable session replay, add the `SessionReplay` plugin to the plugins list **after** the `Observability` plugin. Session replay depends on the Observability plugin being present and initialized first.

Here's how:

<CodeGroup>
  ```kotlin title="Enable session replay" theme={null}
      import com.launchdarkly.observability.plugin.Observability
      import com.launchdarkly.observability.replay.plugin.SessionReplay

      val mobileKey = "example-mobile-key"

      val ldConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(
            Components.plugins().setPlugins(
              listOf(
                Observability(this@BaseApplication, mobileKey),
                SessionReplay()  // depends on Observability being present first
              )
            )
          )
          .build()
  ```
</CodeGroup>

**Important notes:**

* `SessionReplay` depends on `Observability`. If Observability is missing or listed after SessionReplay, the plugin logs an error and stays inactive.
* Observability runs fine without SessionReplay. Adding SessionReplay extends the Observability pipeline to include session recording.

### 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 `enabled` to `false` in `ReplayOptions`, then call `LDReplay.start()` when you're ready to begin recording.

First, configure the plugin with `enabled = false`:

<CodeGroup>
  ```kotlin title="Manual start configuration" theme={null}
      import com.launchdarkly.observability.plugin.Observability
      import com.launchdarkly.observability.replay.plugin.SessionReplay
      import com.launchdarkly.observability.replay.ReplayOptions

      val mobileKey = "example-mobile-key"

      val ldConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(
            Components.plugins().setPlugins(
              listOf(
                Observability(this@BaseApplication, mobileKey),
                SessionReplay(
                  options = ReplayOptions(
                    enabled = false // Don't start recording automatically
                  )
                )
              )
            )
          )
          .build()

      val context = LDContext.create("example-context-key")
      val client = LDClient.init(this@BaseApplication, ldConfig, context, 0)
  ```
</CodeGroup>

Then, start the session replay plugin when appropriate, such as after receiving end user consent or when a feature flag enables session replay.

<CodeGroup>
  ```kotlin title="Start recording" theme={null}
      import com.launchdarkly.observability.sdk.LDReplay

      // Start recording after user consent or feature flag check
      LDReplay.start()
  ```

  ```kotlin title="Start recording with feature flag" theme={null}
      import com.launchdarkly.observability.sdk.LDReplay

      // Start recording based on a feature flag
      val replayEnabled = LDClient.get().boolVariation("enable-session-replay", false)
      if (replayEnabled) {
          LDReplay.start()
      }
  ```

  ```kotlin title="Stop recording" theme={null}
      import com.launchdarkly.observability.sdk.LDReplay

      LDReplay.stop()
  ```

  ```kotlin title="Flush buffered events" theme={null}
      import com.launchdarkly.observability.sdk.LDReplay

      // Immediately export any queued replay events
      LDReplay.flush()
  ```
</CodeGroup>

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

### Session replay configuration options

You can customize session replay behavior by passing a `ReplayOptions` object to the `SessionReplay` constructor:

<CodeGroup>
  ```kotlin title="Session replay options" theme={null}
      import com.launchdarkly.observability.plugin.Observability
      import com.launchdarkly.observability.replay.plugin.SessionReplay
      import com.launchdarkly.observability.replay.ReplayOptions
      import com.launchdarkly.observability.replay.PrivacyProfile

      val mobileKey = "example-mobile-key"

      val ldConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(
            Components.plugins().setPlugins(
              listOf(
                Observability(this@BaseApplication, mobileKey),
                SessionReplay(
                  options = ReplayOptions(
                    privacyProfile = PrivacyProfile(
                      maskTextInputs = true,
                      maskText = true
                    ),
                    capturePeriodMillis = 1000,
                    debug = false
                  )
                )
              )
            )
          )
          .build()
  ```
</CodeGroup>

The available `ReplayOptions` configuration options are:

* **privacyProfile**: Controls how UI elements are masked in the replay. To learn more, read [Privacy options](#privacy-options).
* **capturePeriodMillis**: Period between UI captures in milliseconds. Defaults to `1000` (1 second).
* **debug**: Enables verbose logging when set to `true`. Defaults to `false`.

**Note:** Service configuration options like `serviceName` and `serviceVersion` are set in `ObservabilityOptions`, not in `ReplayOptions`.

### Privacy options

The `PrivacyProfile` class controls how UI elements are masked during session replay. Session replay for Android uses Jetpack Compose semantics to identify and mask UI elements. By default, text inputs are masked to protect user privacy.

Here's how to configure privacy settings:

<CodeGroup>
  ```kotlin title="Privacy profile configuration" theme={null}
      import com.launchdarkly.observability.plugin.Observability
      import com.launchdarkly.observability.replay.plugin.SessionReplay
      import com.launchdarkly.observability.replay.ReplayOptions
      import com.launchdarkly.observability.replay.PrivacyProfile

      val mobileKey = "example-mobile-key"

      val ldConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
          .mobileKey(mobileKey)
          .plugins(
            Components.plugins().setPlugins(
              listOf(
                Observability(this@BaseApplication, mobileKey),
                SessionReplay(
                  options = ReplayOptions(
                    privacyProfile = PrivacyProfile(
                      maskTextInputs = true,
                      maskText = false
                    )
                  )
                )
              )
            )
          )
          .build()
  ```
</CodeGroup>

The available privacy options are:

* **maskTextInputs**: When `true`, masks all text input fields including editable text and paste operations. Defaults to `true`.
* **maskText**: When `true`, masks all non-input text elements in the UI. Defaults to `false`.
* **maskBySemanticsKeywords**: When `true`, masks sensitive views that contain password fields or text matching sensitive keywords. Defaults to `false`.

#### Sensitive keywords

When `maskBySemanticsKeywords` is enabled, the SDK automatically masks any Compose UI text or content descriptions containing predetermined keywords. Keywords you specify are not case-sensitive. For the current set of keywords, read [`PrivacyProfile`](https://github.com/launchdarkly/observability-sdk/blob/main/sdk/%40launchdarkly/observability-android/lib/src/main/kotlin/com/launchdarkly/observability/replay/PrivacyProfile.kt).

#### Common privacy configurations

For maximum privacy (recommended for production):

<CodeGroup>
  ```kotlin title="Maximum privacy" theme={null}
      privacyProfile = PrivacyProfile(
        maskTextInputs = true,
        maskText = true,
        maskBySemanticsKeywords = true
      )
  ```
</CodeGroup>

For debugging or development, you can turn masking off:

<CodeGroup>
  ```kotlin title="No masking" theme={null}
      privacyProfile = PrivacyProfile(
        maskTextInputs = false,
        maskText = false,
        maskBySemanticsKeywords = false
      )
  ```
</CodeGroup>

For selective masking, which masks inputs and sensitive data but shows regular text:

<CodeGroup>
  ```kotlin title="Selective masking" theme={null}
      privacyProfile = PrivacyProfile(
        maskTextInputs = true,
        maskText = false,
        maskBySemanticsKeywords = true
      )
  ```
</CodeGroup>

### Custom masking with ld

Mask

In addition to the privacy profile settings, you can explicitly mask individual UI elements by using the `.ldMask()` modifier. This is useful when you need to mask specific sensitive fields while allowing other content to remain visible.

#### Masking XML views

For traditional Android XML-based views, you can mask any `View` by calling the `.ldMask()` extension function:

<CodeGroup>
  ```kotlin title="Masking XML views" theme={null}
      import com.launchdarkly.observability.api.ldMask

      class LoginActivity : AppCompatActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_login)

              val password = findViewById<EditText>(R.id.password)
              password.ldMask() // mask this field in session replay
          }
      }
  ```
</CodeGroup>

#### Masking Jetpack Compose elements

For Jetpack Compose, you can add the `.ldMask()` modifier to any composable to mask it in session replay recordings:

<CodeGroup>
  ```kotlin title="Masking Compose elements" theme={null}
      import com.launchdarkly.observability.api.ldMask

      @Composable
      fun CreditCardField() {
          var number by remember { mutableStateOf("") }
          TextField(
              value = number,
              onValueChange = { number = it },
              modifier = Modifier
                  .fillMaxWidth()
                  .ldMask() // mask this composable in session replay
          )
      }
  ```
</CodeGroup>

#### Unmasking elements

You can also explicitly unmask elements that would otherwise be masked by the privacy profile settings using the `.ldUnmask()` modifier:

<CodeGroup>
  ```kotlin title="Unmasking elements" theme={null}
      import com.launchdarkly.observability.api.ldUnmask

      @Composable
      fun PublicInfoField() {
          var info by remember { mutableStateOf("") }
          TextField(
              value = info,
              onValueChange = { info = it },
              modifier = Modifier
                  .fillMaxWidth()
                  .ldUnmask() // explicitly unmask this field
          )
      }
  ```
</CodeGroup>

The `.ldMask()` and `.ldUnmask()` modifiers give you fine-grained control over which UI elements are masked in session replay recordings, allowing you to balance privacy protection with useful debugging information.

For more information on session replay configuration, read [Configuration for session replay](/sdk/features/session-replay-config).

## 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](/sdk/features/observability-config-client-side)
* [Configuration for session replay](/sdk/features/session-replay-config)
* [Errors](/sdk/features/observability-errors#android)
* [Logs](/sdk/features/observability-logs#android)
* [Metrics](/sdk/features/observability-metrics#android)
* [Tracing](/sdk/features/observability-traces#android)

## Review observability data in LaunchDarkly

After you initialize the SDK and observability plugin, your application automatically starts sending observability data back to LaunchDarkly. You can review this information in the LaunchDarkly user interface. To learn how, read [Observability](/home/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 metrics](/home/metrics/autogen/observability).
