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

# Configuration for session replay

<View title="Developer" />

<View title="Federal docs" />

<View title="EU docs">
  <Danger>
    **Session replay is not available in the LaunchDarkly European Union (EU) instance**

    To learn more, read <a href="/docs/home/infrastructure/eu">LaunchDarkly in the European Union (EU)</a>.
  </Danger>
</View>

This topic explains how to configure the SDK session replay plugin.

The session replay plugin supports several features, including privacy controls, WebGL capture (JavaScript SDKs), manual control of session recording, and retrieving session URLs on the client. After the SDK and session replay plugin are initialized, you can access these features from within your application.

The session replay plugin is available in JavaScript-based client-side SDKs and mobile SDKs. To get started with the session replay plugin, read the observability reference guide for your SDK. Use the docs site navigation on the left, or find your SDK under [Observability SDKs](/docs/sdk/observability#observability-sdks).

Details about each SDK's configuration are available in the SDK-specific sections below:

* [Client-side SDKs](#client-side-sdks)
* [Mobile SDKs](#mobile-sdks)

## Client-side SDKs

This feature is available in the observability plugin for the following client-side SDKs:

* [JavaScript](#javascript)
* [React Web](#react-web)
* [Vue](#vue)

## Mobile SDKs

This feature is available in the observability plugin for the following mobile SDKs:

* [Android](#android)
* [Flutter](#flutter)
* [React Native](#react-native)

### JavaScript

<Accordion title="Expand JavaScript code sample">
  The session replay plugin supports the following features. After the SDK and session replay plugin are initialized, you can access these from within your application.

  #### Privacy

  When you [configure the plugin options](/docs/sdk/observability/javascript#configure-the-plugin-options), you can choose from the following privacy settings:

  * set `privacySetting` to `default` to obfuscate all inputs and any text that matches commonly used regex expressions for personally identifiable information (PII).
  * set `privacySetting` to `strict` to obfuscate all HTML DOM text and images.
  * set `privacySetting` to `none` if you don't want to obfuscate anything.

  By default, `strict` privacy mode is enabled. This provides the safest option as no PII should be captured, but it may limit session replay usability.

  With `default` privacy mode, the plugin obfuscates all inputs and any text that matches commonly used regex expressions for personally identifiable information (PII). This functionality offers a base level protection from recording info such as addresses, phone numbers, social security numbers, and more. It does not obfuscate any images or media content. It may obfuscate other, non-PII text if that text matches the expressions that the plugin is using.

  <Accordion title="Expand Regex expressions used in default privacy mode">
    Here are the regex expressions that the plugins use when `privacySetting` is set to `default`:

    <CodeGroup>
      ```text title="Regex obfuscated when 'privacySetting' is 'default'" lines wrap theme={null}
        Email: '[a-zA-Z0-9.!#$%&'*+=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:.[a-zA-Z0-9-]+)*'
        SSN: '[0-9]{3}-?[0-9]{2}-?[0-9]{4}'
        Phone number: '[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}'
        Credit card: '[0-9]{4}-?[0-9]{4}-?[0-9]{4}-?[0-9]{4}'
        Unformatted SSN, phone number, credit card: '[0-9]{9,16}'
        Address: '[0-9]{1,5}.?[0-9]{0,3}\s[a-zA-Z]{2,30}\s[a-zA-Z]{2,15}'
        IP address: '(?:[0-9]{1,3}.){3}[0-9]{1,3}'
      ```
    </CodeGroup>
  </Accordion>

  If you need additional customization, you can define a function to edit or remove data in request/response pairs, and include the function in the `networkRecording.requestResponseSanitizer` option in the plugin. To learn more, read [`RequestResponsePair`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/modules/client.html#requestresponsepair) and [`HighlightOptions`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/types/client_types_types.HighlightOptions.html).

  In addition to setting the `privacySetting` for the plugins, you can also make adjustments at the HTML element level:

  * Add `className="highlight-block"` to elements that should be ignored. When the session recording is replayed, an empty placeholder replaces the content.
  * Add `className="highlight-mask"` to obfuscate specific HTML elements.
  * Add `className="highlight-ignore"` to input elements to preserve the styling of the input element, but ignore all end user input. This class is only available for `<input>` elements.
  * When `privacySetting` is `default`, you can override obfuscation on a per HTML element basis by adding the `data-hl-record="true"` attribute to the recorded HTML tag.

  You can also customize the class names and selectors used for privacy settings:

  * Set `maskTextClass` to specify a custom class name or RegExp for masking text elements. Default is `'highlight-mask'`.
  * Set `maskTextSelector` to specify a CSS selector for masking text elements and their descendants.
  * Set `ignoreClass` to specify a custom class name for ignoring input elements. Default is `'highlight-ignore'`.
  * Set `ignoreSelector` to specify a CSS selector for ignoring input elements.
  * Set `blockClass` to specify a custom class name or RegExp for blocking elements completely. Default is `'highlight-block'`.
  * Set `blockSelector` to specify a CSS selector for blocking elements completely.

  Here's an example of using custom privacy classes:

  <CodeGroup>
    ```js title="Custom privacy classes example" lines wrap theme={null}
    new SessionReplay({
      maskTextClass: 'my-mask-class',
      maskTextSelector: '[data-sensitive="true"]',
      ignoreClass: 'my-ignore-class', 
      ignoreSelector: '[data-ignore-input="true"]',
      blockClass: 'my-block-class',
      blockSelector: '[data-block="true"]'
    })
    ```
  </CodeGroup>

  #### Record network request headers and bodies

  By default, the session replay Network tab shows the URL, method, status, timing, and size of each request. To also show request and response headers and bodies, set the `networkRecording` option on the session replay plugin:

  <CodeGroup>
    ```js title="Network recording options, JS SDK v4.x" lines wrap theme={null}
    const client = initialize('example-client-side-id', {
      plugins: [
        new SessionReplay({
          networkRecording: {
            enabled: true,
            recordHeadersAndBody: true
          }
        })
      ]
    });
    ```

    ```js title="Network recording options, JS SDK v3.7+" lines wrap theme={null}
    const context = {
      kind: 'user',
      key: 'example-context-key'
    };

    const client = initialize('example-client-side-id', context, {
      plugins: [
        new SessionReplay({
          networkRecording: {
            enabled: true,
            recordHeadersAndBody: true
          }
        })
      ]
    });
    ```
  </CodeGroup>

  The session replay plugin and the observability plugin each have their own `networkRecording` option. The session replay plugin's option controls what appears in the session replay Network tab. The observability plugin's option controls what is attached to traces. To record headers and bodies in both places, set the option on both plugins.

  The session replay plugin supports the same redaction options as the observability plugin: `networkHeadersToRedact`, `networkBodyKeysToRedact`, `headerKeysToRecord`, `bodyKeysToRecord`, `urlBlocklist`, and `requestResponseSanitizer`. To learn more, read [Recording network requests and WebSocket events](/docs/sdk/features/observability-config-client-side#recording-network-requests-and-websocket-events).

  #### Record canvas

  The session replay plugin can record a snapshot bitmap of an `HTMLCanvasElement` for WebGL capture.

  To set this up, pass the following options when you initialize the plugin:

  <CodeGroup>
    ```js title="Recording options, JS SDK v4.x" lines wrap theme={null}
    const client = initialize('example-client-side-id', {
      plugins: [
        new SessionReplay({
          enableCanvasRecording: true, // enable canvas recording
          samplingStrategy: {
            canvas: 2, // snapshot at 2 fps
            canvasMaxSnapshotDimension: 480, // snapshot at a max 480p resolution
          },
        })
      ]
    });
    ```

    ```js title="Recording options, JS SDK v3.7+" lines wrap theme={null}
    const context = {
      kind: 'user',
      key: 'example-context-key'
    };

    const client = initialize('example-client-side-id', context, {
      plugins: [
        new SessionReplay({
          enableCanvasRecording: true, // enable canvas recording
          samplingStrategy: {
            canvas: 2, // snapshot at 2 fps
            canvasMaxSnapshotDimension: 480, // snapshot at a max 480p resolution
          },
        })
      ]
    });
    ```
  </CodeGroup>

  To learn more, read [`snapshot`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#snapshot).

  #### Retrieve session URLs on the client

  The session replay plugin also provides options for retrieving details about the current recorded session. This can be useful for building a custom integration with the session replay data.

  `getSession` returns details of the current recording session, including a URL to view the session, and a URL for the exact time the method is called, relative to the session recording. For example, suppose an error is thrown in your app and you want to save the session URL to another application. You can use the session details `urlWithTimestamp` to set the player to the time when the error occurs.

  Here's how:

  <CodeGroup>
    ```js title="Get session details" lines wrap theme={null}
    LDRecord.getSession().then(({url, urlWithTimestamp}) => {
      console.log(url, urlWithTimestamp);
    });
    ```
  </CodeGroup>

  To learn more, read [`getSession`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#getsession).

  To determine whether the current session is recording, use `getRecordingState`:

  <CodeGroup>
    ```js title="Get session details" lines wrap theme={null}
    // returns 'NotRecording' or 'Recording'
    const recordingState = LDRecord.getRecordingState();
    ```
  </CodeGroup>

  To learn more, read [`getRecordingState`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#getrecordingstate).

  #### Add session properties

  Use `LDRecord.addSessionProperties()` to add custom session-level properties. These properties are attached to the current session and are searchable in LaunchDarkly, but unlike `track()` events, they do not create timeline events.

  Call this after the session has started. If you start sessions manually, wait for `LDRecord.start()` to complete before adding properties so they are recorded correctly.

  Here's how:

  <CodeGroup>
    ```js title="Add session properties" lines wrap theme={null}
    LDRecord.addSessionProperties({
      plan: 'pro',
      favoriteColor: 'purple',
    });
    ```
  </CodeGroup>

  Use session properties to attach metadata to sessions that you want to search or filter by later, without cluttering the timeline with track events.

  To learn more, read [`addSessionProperties`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#addsessionproperties).

  #### Record styles, images, and videos

  When you [configure the plugin options](/docs/sdk/observability/javascript#configure-the-plugin-options) for the session replay plugin, you can explicitly request to inline stylesheets, images, or videos into the recording. This means that assets that are local to the client are serialized into the session replay recording and will be valid on replay. Some common reasons to turn on these settings include: firewall blocking CSS stylesheet access at time of replay, `<video>` tags that reference `blob:` in-memory video streams, and images that are transformed client-side.

  Here's how:

  <CodeGroup>
    ```js title="Inline options" lines wrap theme={null}
    const options = {
      plugins: [
        new SessionReplay({
            inlineStylesheet: true,
            inlineImages: true,
            inlineVideos: true,
          },
        })
      ]
    };
    ```
  </CodeGroup>

  Inlining may negatively affect performance, so we only recommend setting these options if you are encountering issues with client-local stylesheets or images. Turning the settings on can also trigger CORS errors. To learn more, read:

  * [`inlineStylesheet`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/types/client_types_types.HighlightOptions.html#default-9)
  * [`inlineImages`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/types/client_types_types.HighlightOptions.html#default-8)
  * [`inlineVideos`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/types/client_types_types.HighlightOptions.html#default-10)

  #### Canvas and WebGL

  When you [configure the plugin options](/docs/sdk/observability/javascript#configure-the-plugin-options) for the session replay plugin, you can set up recording of `<canvas>` elements. This includes `<canvas>` elements that use WebGL.

  Here's how:

  <CodeGroup>
    ```js title="Recording options" lines wrap theme={null}
    const options = {
      plugins: [
        new SessionReplay({
          enableCanvasRecording: true, // enable canvas recording
          samplingStrategy: {
            canvasManualSnapshot: 2, // snapshot at 2 fps
            canvasMaxSnapshotDimension: 480, // snapshot at a max 480p resolution
          },
        })
      ]
    };
    ```
  </CodeGroup>

  For WebGL canvas recording, the `canvasManualSnapshot` option is used to enable manual capture of the canvas. This is necessary to avoid capturing the WebGL buffer while it is no longer in memory.

  The `samplingStrategy` options include the following:

  * `samplingStrategy.canvas` is the frame per second rate used to record the HTML canvas with automated recording. This is the recommended default approach. We recommend using a value of less than 5 to ensure the recording is not too large and does not have issues with playback.
  * `samplingStrategy.canvasManualSnapshot` is the frame per second rate used in manual snapshotting mode. Manual mode may be necessary in some cases, especially for WebGL applications.
  * `samplingStrategy.canvasFactor` is the resolution scaling factor applied to both dimensions of the canvas.
  * `samplingStrategy.canvasMaxSnapshotDimension` is the maximum recording resolution of the largest dimension of the canvas.
  * `samplingStrategy.canvasClearWebGLBuffer` disables WebGL buffer clearing when set to `false`. This may help if the canvas flickers when recording.
  * `samplingStrategy.canvasInitialSnapshotDelay` is the time in milliseconds to wait before the initial snapshot of canvas/video elements.

  After you configure the plugin to your specifications, hook into your WebGL rendering code and call `snapshot`:

  <CodeGroup>
    ```js title="Record snapshot" lines wrap theme={null}
    engine.runRenderLoop(() => {
      scene.render()
      LDRecord.snapshot(canvasElementRef.current)
    })
    ```
  </CodeGroup>

  ##### Working with iframes

  You can record `<canvas>` elements within an `<iframe>`. However, you should be aware of the following caveats:

  * The iframe will not load if the source's origin has a restrictive `X-Frame-Options` header.
  * If the iframe source becomes invalid after some time, or does not render content when inserted into a different domain, the session recording will not show the content that the end user saw.

  By default, LaunchDarkly only supports recording same-origin iframes. If you can initialize the SDK and observability plugin within the `iframe`, you can record the events as a separate session.

  In some cases, you may need to record a [cross-origin iframe](https://learn.microsoft.com/en-us/skype-sdk/ucwa/cross_domainiframe). These are `<iframe>` elements in your application that reference a domain considered to be part of a [different origin](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy). When your iframe uses a `src` tag pointing to a different origin, the iframe is not accessible from the parent page. However, the iframe can still emit messages that the parent page can hear.

  To support cross-origin iframes, set the `recordCrossOriginIframe` option to `true` when you initialize the SDK in both the parent window and the iframe.

  Here's how:

  <CodeGroup>
    ```js title="Plugin options" lines wrap theme={null}
    const options = {
      plugins: [
        new SessionReplay({
          recordCrossOriginIframe: true
        })
      ]
    };
    ```
  </CodeGroup>

  If your application is deployed into a cross-origin iframe of a parent application that you do not control, set the `recordCrossOriginIframe` option to `false`. This starts the recording for the iframe in standalone mode, and records a session with just the contents of the iframe.

  To learn more, read `recordCrossOriginIframe` in [`HighlightOptions`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/types/client_types_types.HighlightOptions.html).

  #### Using a proxy

  If your sessions are not appearing in LaunchDarkly, it may be that requests to LaunchDarkly are being blocked. This may be happening for any of several reasons, including third-party browser extensions, browser configuration, or VPN settings.

  If you have access to your domain's DNS settings, you can set up a proxy from your domain to LaunchDarkly to avoid having requests blocked.

  Here's how:

  1. On your domain, add two `CNAME` records:

     * A `CNAME` record that points `pub.ld.<your_domain>` to `pub.observability.app.launchdarkly.com`.
     * A `CNAME` record that points `otel.ld.<your_domain>` to `otel.observability.app.launchdarkly.com`. This record is optional if you are only using the session replay plugin, but required if you are also using the [observability plugin](/docs/sdk/features/observability-config-client-side).

     Together, these records mean that if you have an app running at `<your_domain>`, your DNS records will point `pub.ld.<your_domain>` and `otel.ld.<your_domain>` to the LaunchDarkly servers.

  2. In your application, set the `backendUrl` option when you [configure the observability plugin](/docs/sdk/observability/javascript#configure-the-plugin-options). Set the `backendUrl` option to `pub.ld.<your_domain>`.

     Here's how:

       <CodeGroup>
         ```js title="Plugin options" lines wrap theme={null}
         // the examples assume your_domain is acme.com

         const options = {
           plugins: [
             new SessionReplay({
               backendUrl: 'https://pub.ld.acme.com',
             })
           ]
         };
         ```
       </CodeGroup>
</Accordion>

### React Web

<Accordion title="Expand React Web code sample">
  The session replay plugin supports the following features. After the SDK and session replay plugin are initialized, you can access these from within your application.

  #### Record canvas

  The session replay plugin can record a snapshot bitmap of an `HTMLCanvasElement` for WebGL capture.

  To set this up, pass the following options when you initialize the plugin:

  <CodeGroup>
    ```js title="Recording options, React Web SDK v3.7+" lines wrap theme={null}
    const LDProvider = withLDProvider({
      clientSideID: 'example-client-side-id',
      context,
      options: {
          plugins: [
            new SessionReplay({
              enableCanvasRecording: true, // enable canvas recording
              samplingStrategy: {
                canvas: 2, // snapshot at 2 fps
                canvasMaxSnapshotDimension: 480, // snapshot at a max 480p resolution
              },
            })
          ]
      }
    })(App);
    ```
  </CodeGroup>

  To learn more, read [`snapshot`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#snapshot).

  #### Manually control session recording

  By default, sessions are automatically recorded after you initialize the session replay plugin. If you want to control recording manually, set `manualStart` to `true` in the plugin options:

  <CodeGroup>
    ```js title="Recording options, React Web SDK v3.7+" lines wrap theme={null}
    const LDProvider = withLDProvider({
      clientSideID: 'example-client-side-id',
      context,
      options: {
        plugins: [
          new SessionReplay({ manualStart: true })
        ]
      }
    })(App);
    ```
  </CodeGroup>

  <Note>
    **LDRecord.start is asynchronous**

    `LDRecord.start()` returns a Promise.
    You must wait for the session to start before calling other session methods such as `addSessionProperties()` or `getSession()`. Otherwise, session data may not be recorded.
  </Note>

  Then, start session replay yourself:

  <CodeGroup>
    ```js title="Start recording" lines wrap theme={null}
    await LDRecord.start({
      silent: false // if true, console.warn messages created in this method are skipped
    });
    ```
  </CodeGroup>

  To stop session replay:

  <CodeGroup>
    ```js title="Stop recording" lines wrap theme={null}
    LDRecord.stop();
    ```
  </CodeGroup>

  To learn more, read [`start`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#start) and [`stop`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#stop).

  #### Retrieve session URLs on the client

  The session replay plugin also provides options for retrieving details about the current recorded session. This can be useful for building a custom integration with the session replay data.

  `getSession` returns details of the current recording session, including a URL to view the session, and a URL for the exact time the method is called, relative to the session recording. For example, suppose an error is thrown in your app and you want to save the session URL to another application. You can use the session details `urlWithTimestamp` to set the player to the time when the error occurs.

  Here's how:

  <CodeGroup>
    ```js title="Get session details" lines wrap theme={null}
    LDRecord.getSession().then(({url, urlWithTimestamp}) => {
      console.log(url, urlWithTimestamp);
    });
    ```
  </CodeGroup>

  To learn more, read [`getSession`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#getsession).

  To determine whether the current session is recording, use `getRecordingState`:

  <CodeGroup>
    ```js title="Get session details" lines wrap theme={null}
    // returns 'NotRecording' or 'Recording'
    const recordingState = LDRecord.getRecordingState();
    ```
  </CodeGroup>

  To learn more, read [`getRecordingState`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#getrecordingstate).

  #### Add session properties

  Use `LDRecord.addSessionProperties()` to add custom session-level properties. These properties are attached to the current session and are searchable in LaunchDarkly, but, unlike `track()` events, they do not create timeline events.

  Call this after the session has started. If you are manually starting sessions, wait for `LDRecord.start()` to complete first.

  <CodeGroup>
    ```js title="Add session properties" lines wrap theme={null}
    LDRecord.addSessionProperties({
      plan: 'pro',
      favoriteColor: 'purple',
    });

    ```
  </CodeGroup>

  Use session properties to attach metadata to sessions that you want to search or filter by later, without cluttering the timeline with track events.

  To learn more, read [`addSessionProperties`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#addsessionproperties).
</Accordion>

### Vue

<Accordion title="Expand Vue code sample">
  The session replay plugin supports the following features. After the SDK and session replay plugin are initialized, you can access these from within your application.

  #### Record canvas

  The session replay plugin can record a snapshot bitmap of an `HTMLCanvasElement` for WebGL capture.

  To set this up, pass the following options when you initialize the plugin:

  <CodeGroup>
    ```js title="Recording options, Vue SDK v3.0" expandable lines wrap theme={null}
    // main.js

    const app = createApp(App)
    app.use(LDVuePlugin, {
      clientSideID: 'example-client-side-id',
      context: { kind: 'user', key: 'example-context-key' },
      ldOptions: {
        plugins: [
          new SessionReplay({
            enableCanvasRecording: true, // enable canvas recording
            samplingStrategy: {
              canvas: 2, // snapshot at 2 fps
              canvasMaxSnapshotDimension: 480, // snapshot at a max 480p resolution
            },
          })
        ]
      }
    })
    app.mount('#app')
    ```

    ```js title="Recording options, Vue SDK v2.4+" lines wrap theme={null}
    // main.js

    const app = createApp(App)
    app.use(LDPlugin, {
      clientSideID: 'example-client-side-id',
      options: {
        plugins: [
          new SessionReplay({
            enableCanvasRecording: true, // enable canvas recording
            samplingStrategy: {
              canvas: 2, // snapshot at 2 fps
              canvasMaxSnapshotDimension: 480, // snapshot at a max 480p resolution
            },
          })
        ]
      }
    })
    app.mount('#app')
    ```
  </CodeGroup>

  #### Manually control session recording

  By default, sessions are automatically recorded after you initialize the session replay plugin. If you want to control recording manually, set `manualStart` to `true` in the plugin options:

  <CodeGroup>
    ```js title="Recording options, Vue SDK v3.0" lines wrap theme={null}
    // main.js

    const app = createApp(App)
    app.use(LDVuePlugin, {
      clientSideID: 'example-client-side-id',
      context: { kind: 'user', key: 'example-context-key' },
      ldOptions: {
        plugins: [
          new SessionReplay({ manualStart: true })
        ]
      }
    })
    app.mount('#app')
    ```

    ```js title="Recording options, Vue SDK v2.4+" lines wrap theme={null}
    // main.js

    const app = createApp(App)
    app.use(LDPlugin, {
      clientSideID: 'example-client-side-id',
      options: {
        plugins: [
          new SessionReplay({ manualStart: true })
        ]
      }
    })
    app.mount('#app')
    ```
  </CodeGroup>

  <Note>
    **LDRecord.start is asynchronous**

    `LDRecord.start()` returns a Promise.
    You must wait for the session to start before calling other session methods such as `addSessionProperties()` or `getSession()`. Otherwise, session data may not be recorded.
  </Note>

  Then, start session replay yourself:

  <CodeGroup>
    ```js title="Start recording" lines wrap theme={null}
    await LDRecord.start({
      silent: false // if true, console.warn messages created in this method are skipped
    });
    ```
  </CodeGroup>

  To stop session replay:

  <CodeGroup>
    ```js title="Stop recording" lines wrap theme={null}
    LDRecord.stop();
    ```
  </CodeGroup>

  To learn more, read [`start`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#start) and [`stop`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#stop).

  #### Retrieve session URLs on the client

  The session replay plugin also provides options for retrieving details about the current recorded session. This can be useful for building a custom integration with the session replay data.

  `getSession` returns details of the current recording session, including a URL to view the session, and a URL for the exact time the method is called, relative to the session recording. For example, suppose an error is thrown in your app and you want to save the session URL to another application. You can use the session details `urlWithTimestamp` to set the player to the time when the error occurs.

  Here's how:

  <CodeGroup>
    ```js title="Get session details" lines wrap theme={null}
    LDRecord.getSession().then(({url, urlWithTimestamp}) => {
      console.log(url, urlWithTimestamp);
    });
    ```
  </CodeGroup>

  To learn more, read [`getSession`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#getsession).

  To determine whether the current session is recording, use `getRecordingState`:

  <CodeGroup>
    ```js title="Get session details" lines wrap theme={null}
    // returns 'NotRecording' or 'Recording'
    const recordingState = LDRecord.getRecordingState();
    ```
  </CodeGroup>

  To learn more, read [`getRecordingState`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#getrecordingstate).

  #### Add session properties

  Use `LDRecord.addSessionProperties()` to add custom session-level properties. These properties are attached to the current session and are searchable in LaunchDarkly, but, unlike `track()` events, they do not create timeline events.

  Call this after the session has started. If you are manually starting sessions, wait for `LDRecord.start()` to complete first.

  <CodeGroup>
    ```js title="Add session properties" lines wrap theme={null}
    LDRecord.addSessionProperties({
      plan: 'pro',
      favoriteColor: 'purple',
    });
    ```
  </CodeGroup>

  Use session properties to attach metadata to sessions that you want to search or filter by later, without cluttering the timeline with track events.

  To learn more, read [`addSessionProperties`](https://launchdarkly.github.io/observability-sdk/packages/@launchdarkly/observability/interfaces/api_record.Record.html#addsessionproperties).
</Accordion>

### Android

<Accordion title="Expand Android code sample">
  The session replay plugin for Android supports the following features. After the SDK and session replay plugin are initialized, you can access these from within your application.

  #### Privacy

  The Android session replay plugin uses `PrivacyProfile` to control how UI elements are masked. By default, text inputs are masked. Session replay for Android uses Jetpack Compose semantics to identify and mask UI elements. Test thoroughly before releasing to ensure masking meets your requirements.

  Here's how to configure privacy settings:

  <CodeGroup>
    ```kotlin title="Privacy profile configuration" expandable lines wrap theme={null}
    import com.launchdarkly.observability.replay.PrivacyProfile

    val ldConfig = LDConfig.Builder(AutoEnvAttributes.Enabled)
      .mobileKey("example-mobile-key")
      .plugins(
        Components.plugins().setPlugins(
          listOf(
            Observability(
              this@BaseApplication,
              Options(
                instrumentations = listOf(
                  ReplayInstrumentation(
                    options = ReplayOptions(
                      privacyProfile = PrivacyProfile(
                        maskTextInputs = true,
                        maskText = false,
                        maskBySemanticsKeywords = true
                      )
                    )
                  )
                )
              )
            )
          )
        )
      )
      .build()
    ```
  </CodeGroup>

  ##### 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 most up to date 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).
</Accordion>

### Flutter

<Accordion title="Expand Flutter code sample">
  To learn how to install and initialize the session replay plugin, read [Configure session replay](/docs/sdk/observability/flutter#configure-session-replay) in the Flutter SDK observability reference.

  Session replay for Flutter is supported only on iOS and Android. Session replay is not supported on web.

  The session replay plugin for Flutter supports the following features:

  #### Privacy

  Enable session replay and configure privacy options by passing `SessionReplayOptions` to `LDObserve.init` or `LDObserve.initStandalone`:

  <CodeGroup>
    ```dart title="Privacy options" lines wrap theme={null}
    LDObserve.init(
      client,
      observability: const ObservabilityOptions(serviceName: 'my-flutter-app'),
      replay: const SessionReplayOptions(
        isEnabled: true,
        privacy: PrivacyOptions(
          maskTextInputs: true,
          maskWebViews: false,
          maskLabels: false,
          maskImages: false,
        ),
      ),
    );
    ```
  </CodeGroup>

  The available privacy options are:

  * **maskTextInputs**: Masks all text input fields. Defaults to `true`.
  * **maskWebViews**: Masks the contents of web views. Defaults to `false`.
  * **maskLabels**: Masks all text labels. Defaults to `false`.
  * **maskImages**: Masks all images. Defaults to `false`.
  * **minimumAlpha**: The opacity threshold, from `0.0` to `1.0`, below which the plugin treats a widget as invisible and skips it during capture and masking. Defaults to `0.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 of `maskLabels`, which controls whether the plugin paints over text in captured frames. To learn more, read [Record taps](/docs/sdk/observability/flutter#record-taps).

  #### Per-widget masking

  Use `LDMask` to redact an individual widget's subtree in all captured frames, `LDIgnore` to exclude a subtree from session replay entirely, and `LDUnmask` to exempt a subtree from global masking rules:

  <CodeGroup>
    ```dart title="LDMask, LDIgnore, and LDUnmask" lines wrap theme={null}
    // Redact a sensitive widget
    LDMask(
      child: Text(creditCardNumber),
    )

    // Exclude a subtree from session replay entirely
    LDIgnore(
      child: VideoPlayer(controller),
    )

    // Reveal one field even when maskTextInputs is true
    LDUnmask(
      child: TextField(controller: searchController),
    )
    ```
  </CodeGroup>

  `LDUnmask` only overrides global masking rules. It does not override an explicit `LDMask` or `LDIgnore`.

  You can also match widgets by `Type` or `Key` instead of wrapping them, using the `maskWidgetTypes`, `maskWidgetKeys`, `unmaskWidgetTypes`, `unmaskWidgetKeys`, `ignoreWidgetTypes`, and `ignoreWidgetKeys` options in `PrivacyOptions`. To learn more, read [Mask by widget type or key](/docs/sdk/observability/flutter#mask-by-widget-type-or-key).

  #### Capture options

  On Android and iOS, `SessionReplayOptions` also accepts several capture options. `sampleRate` is the probability from `0.0` to `1.0` that session replay starts when enabled. `frameRate` is the target capture rate in frames per second. `scale` is the resolution multiplier for captured frames. `sampleRate`, `frameRate`, and `scale` default to `1.0`. `imageQuality` is the JPEG encoding quality of exported frames, from `0.0` (lowest quality, smallest payload) to `1.0` (highest quality, largest payload), and defaults to `0.3`. To learn more, read [Session replay configuration options](/docs/sdk/observability/flutter#session-replay-configuration-options).
</Accordion>

### React Native

<Accordion title="Expand React Native code sample">
  The session replay plugin for React Native supports the following features. After the SDK and session replay plugin are initialized, you can access these from within your application.

  Session replay for React Native is available on **iOS** and **Android**. To learn how to install and initialize the plugin, read [Configure session replay](/docs/sdk/observability/react-native#configure-session-replay) in the React Native SDK observability reference.

  #### Privacy

  The React Native session replay plugin masks UI elements through options passed to `createSessionReplayPlugin` or `configureSessionReplay`. By default, text inputs are masked.

  For each view, the SDK evaluates these rules in order and stops at the first that applies:

  1. **Explicit masking (highest priority)**: The view, or any of its ancestors, is wrapped in `<LDMask>` or has a `testID` matched by `maskTestIDs`.
  2. **Explicit unmasking**: The view, or any of its ancestors, is wrapped in `<LDUnmask>` or has a `testID` matched by `unmaskTestIDs`.
  3. **Global configuration**: The global privacy options (`maskTextInputs`, `maskLabels`, `maskImages`, `maskWebViews`) apply.

  If two rules conflict at the same level, masking takes precedence over unmasking.

  Here's how to configure privacy settings:

  <CodeGroup>
    ```js title="Privacy options" lines wrap theme={null}
    import { createSessionReplayPlugin } from '@launchdarkly/session-replay-react-native';

    const sessionReplay = createSessionReplayPlugin({
    maskTextInputs: true,
    maskWebViews: false,
    maskLabels: false,
    maskImages: false,
    maskTestIDs: ['password', 'ssn'],
    unmaskTestIDs: ['greeting'],
    // iOS only
    minimumAlpha: 0.02,
    });
    ```
  </CodeGroup>

  The available privacy options are:

  * **maskTextInputs**: When `true`, masks all `<TextInput>` components. Defaults to `true`.
  * **maskWebViews**: When `true`, masks the contents of `<WebView>` components. Web views are rendered as blank rectangles in session replays. Defaults to `false`.
  * **maskLabels**: When `true`, masks all `<Text>` components. Defaults to `false`.
  * **maskImages**: When `true`, masks all `<Image>` components. Defaults to `false`.
  * **maskTestIDs**: Masks an array of `testID` values. Matches use exact string equality. Applied on iOS and Android.
  * **unmaskTestIDs**: Excludes an array of `testID` values from masking. Matches use exact string equality. Applied on iOS and Android.
  * **minimumAlpha** (iOS only): Minimum alpha value for view visibility in recordings. Defaults to `0.02`.

  To redact a subtree without giving it a `testID`, wrap it in `<LDMask>`. `<LDMask>` propagates to all its descendants. After you wrap a subtree in `<LDMask>`, nothing inside of it can opt out of masking.

  <CodeGroup>
    ```jsx title="Wrapper components" lines wrap theme={null}
    import { LDMask, LDUnmask } from '@launchdarkly/session-replay-react-native';

    <LDMask>
    <Text>account balance: $1,234</Text>
    </LDMask>;

    <LDUnmask>
    <Text>display even when maskLabels is on</Text>
    </LDUnmask>;
    ```
  </CodeGroup>

  #### Manually control session recording

  By default, session recording starts when the plugin registers. To control recording manually, set `isEnabled` to `false` in the plugin options, then call `startSessionReplay()` when you are ready. `startSessionReplay()` starts recording regardless of the configured `isEnabled` value, and recording continues until you call `stopSessionReplay()`. Deferred recording requires session replay plugin version 0.24.0 or later.

  Here is an example:

  <CodeGroup>
    ```js title="Manual start" lines wrap theme={null}
    import {
    createSessionReplayPlugin,
    startSessionReplay,
    stopSessionReplay,
    } from '@launchdarkly/session-replay-react-native';

    const sessionReplay = createSessionReplayPlugin({ isEnabled: false });

    // Start recording after user consent or a feature flag check:
    await startSessionReplay();

    // Stop recording:
    await stopSessionReplay();
    ```
  </CodeGroup>

  To learn more, read [Initialize session replay manually](/docs/sdk/observability/react-native#initialize-session-replay-manually) in the React Native SDK observability reference.
</Accordion>
