---
title: "JavaScript SDK: Replays"
description: "Record and replay user interactions for bug reports with the Gleap JavaScript SDK. Follow the integration code examples."
url: https://docs.gleap.ai/en/articles/399-javascript-sdk-replays
collection: "JavaScript"
updated: 2026-11-01
language: en
---

# JavaScript SDK: Replays

Record and replay user interactions for bug reports with the Gleap JavaScript SDK. Follow the integration code examples.

Replays for our JavaScript SDK allow you to record and replay users' interactions on the web. This is especially handy for bug reports, where you'd like to replay the last actions a user took before a bug occured.

## Enable replays

Turn on Web replays under Settings → Developer → Developer options → Replays. Reload your app after saving. Replays are in beta; check the current plan requirement and test them in a staging environment first.

## Configuration options

This document provides detailed information on the configuration options available for replays. **You must set the replay options before** `Gleap.initialize("API_KEY");` **gets called**.

```js
Gleap.setReplayOptions({
  // Replay options go here.
});
```

### Available options

<table style="min-width: 75px;"><colgroup><col style="min-width: 25px;"><col style="min-width: 25px;"><col style="min-width: 25px;"></colgroup><tbody><tr><th colspan="1" rowspan="1"><p>Key</p></th><th colspan="1" rowspan="1"><p>Default</p></th><th colspan="1" rowspan="1"><p>Description</p></th></tr><tr><td colspan="1" rowspan="1"><p><code>blockClass</code></p></td><td colspan="1" rowspan="1"><p><code>'rr-block'</code></p></td><td colspan="1" rowspan="1"><p>Use a string or RegExp to configure which elements should be blocked. Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">privacy chapter</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>blockSelector</code></p></td><td colspan="1" rowspan="1"><p><code>null</code></p></td><td colspan="1" rowspan="1"><p>Use a string to configure which selector should be blocked. Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">privacy chapter</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>ignoreClass</code></p></td><td colspan="1" rowspan="1"><p><code>'rr-ignore'</code></p></td><td colspan="1" rowspan="1"><p>Use a string or RegExp to configure which elements should be ignored. Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">privacy chapter</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>ignoreSelector</code></p></td><td colspan="1" rowspan="1"><p><code>null</code></p></td><td colspan="1" rowspan="1"><p>Use a string to configure which selector should be ignored. Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">privacy chapter</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>ignoreCSSAttributes</code></p></td><td colspan="1" rowspan="1"><p><code>null</code></p></td><td colspan="1" rowspan="1"><p>Array of CSS attributes that should be ignored.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>maskTextClass</code></p></td><td colspan="1" rowspan="1"><p><code>'rr-mask'</code></p></td><td colspan="1" rowspan="1"><p>Use a string or RegExp to configure which elements should be masked: their text, and the values of fields inside them. Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">privacy chapter</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>maskTextSelector</code></p></td><td colspan="1" rowspan="1"><p><code>null</code></p></td><td colspan="1" rowspan="1"><p>Use a string to configure which selector should be masked: text, and the values of fields inside matching elements. Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">privacy chapter</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>maskAllInputs</code></p></td><td colspan="1" rowspan="1"><p><code>false</code></p></td><td colspan="1" rowspan="1"><p>Mask every input value as <code>*</code>, in replays and (from SDK 18.1.1) screenshots. Off by default; the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">fields masked automatically</a> stay masked either way.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>maskInputOptions</code></p></td><td colspan="1" rowspan="1"><p><code>{ password: true }</code></p></td><td colspan="1" rowspan="1"><p>Mask some kinds of input as <code>*</code>, in replays and (from SDK 18.1.1) screenshots. Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#mask-input-options">list</a>. From SDK 18.1.1, password fields stay masked whatever you pass.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>maskInputFn</code></p></td><td colspan="1" rowspan="1"><p>-</p></td><td colspan="1" rowspan="1"><p><code>(text, element) =&gt; string</code>: customize how the values that <code>maskInputOptions</code> or <code>maskAllInputs</code> mask are recorded, in replays and (from SDK 18.1.1) screenshots. Not used for the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#privacy">fields masked automatically</a>, which are always masked as <code>*</code>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>maskTextFn</code></p></td><td colspan="1" rowspan="1"><p>-</p></td><td colspan="1" rowspan="1"><p>Customize mask text content recording logic.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>slimDOMOptions</code></p></td><td colspan="1" rowspan="1"><p><code>{}</code></p></td><td colspan="1" rowspan="1"><p>Remove unnecessary parts of the DOM.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>dataURLOptions</code></p></td><td colspan="1" rowspan="1"><p><code>{}</code></p></td><td colspan="1" rowspan="1"><p>Canvas image format and quality. This parameter will be passed to the <code>OffscreenCanvas.convertToBlob()</code>. Using this parameter effectively reduces the size of the recorded data.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>inlineStylesheet</code></p></td><td colspan="1" rowspan="1"><p><code>true</code></p></td><td colspan="1" rowspan="1"><p>Whether to inline the stylesheet in the events.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>hooks</code></p></td><td colspan="1" rowspan="1"><p><code>{}</code></p></td><td colspan="1" rowspan="1"><p>Hooks for events.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>packFn</code></p></td><td colspan="1" rowspan="1"><p>-</p></td><td colspan="1" rowspan="1"><p>Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#storage-optimization-recipe">storage optimization recipe</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>sampling</code></p></td><td colspan="1" rowspan="1"><p>-</p></td><td colspan="1" rowspan="1"><p>Refer to the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#storage-optimization-recipe">storage optimization recipe</a>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>recordCanvas</code></p></td><td colspan="1" rowspan="1"><p><code>false</code></p></td><td colspan="1" rowspan="1"><p>Whether to record the canvas element. Available options: <code>false</code>, <code>true</code>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>recordCrossOriginIframes</code></p></td><td colspan="1" rowspan="1"><p><code>false</code></p></td><td colspan="1" rowspan="1"><p>Whether to record cross origin iframes. rrweb (see the <a target="_blank" rel="noopener noreferrer nofollow" class="linktype-link link" data-linktype="link" href="#cross-origin-iframes">docs</a> below) has to be injected in each child iframe for this to work. Available options: <code>false</code>, <code>true</code>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>recordAfter</code></p></td><td colspan="1" rowspan="1"><p><code>'load'</code></p></td><td colspan="1" rowspan="1"><p>If the document is not ready, then the recorder will start recording after the specified event is fired. Available options: <code>DOMContentLoaded</code>, <code>load</code>.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>inlineImages</code></p></td><td colspan="1" rowspan="1"><p><code>false</code></p></td><td colspan="1" rowspan="1"><p>Whether to record the image content.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>collectFonts</code></p></td><td colspan="1" rowspan="1"><p><code>false</code></p></td><td colspan="1" rowspan="1"><p>Whether to collect fonts in the website.</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>userTriggeredOnInput</code></p></td><td colspan="1" rowspan="1"><p><code>false</code></p></td><td colspan="1" rowspan="1"><p>Whether to add <code>userTriggered</code> on input events that indicates if this event was triggered directly by the user or not. What is <code>userTriggered</code>?</p></td></tr><tr><td colspan="1" rowspan="1"><p><code>plugins</code></p></td><td colspan="1" rowspan="1"><p><code>[]</code></p></td><td colspan="1" rowspan="1"><p>Load plugins to provide extended record functions. What are <code>plugins</code>?</p></td></tr></tbody></table>

### Storage Optimization Recipe

Use the sampling config in the recording can reduce the storage size by dropping some events:

#### Block DOM element

Some DOM elements may emit lots of events, and some of them may not be the thing user cares about. So you can use the block class to ignore these kinds of elements.

Some common patterns may emit lots of events are:

-   long list
    
-   complex SVG
    
-   element with JS controlled animation
    
-   canvas animations
    

#### Sampling

```js
Gleap.setReplayOptions({
  sampling: {
    // do not record mouse movement
    mousemove: false,
    // do not record mouse interaction
    mouseInteraction: false,
    // set the interval of scrolling event
    scroll: 150,
    // set the interval of media interaction event
    media: 800,
    // set the timing of record input
    input: "last", // When input mulitple characters, only record the final input
  },
});
```

```js
Gleap.setReplayOptions({
   sampling: {
    // Configure which kinds of mouse interaction should be recorded
    mouseInteraction: {
      MouseUp: false,
      MouseDown: false,
      Click: false,
      ContextMenu: false,
      DblClick: false,
      Focus: false,
      Blur: false,
      TouchStart: false,
      TouchEnd: false,
    },
  },
});
```

## Recording canvas

Canvas is a special HTML element, and will not be recorded by replays by default. There are some options for recording and replaying Canvas.

Enable recording Canvas：

```js
Gleap.setReplayOptions({
  recordCanvas: true,
  sampling: {
    canvas: 15,
  },
  // optional image format settings
  dataURLOptions: {
    type: "image/webp",
    quality: 0.6,
  },
});
```

## Cross origin iframes

To facilitate the replay functionality for cross-origin iframes, some extra configurations are required. Gleap employs rrweb for capturing the replay sessions. For a comprehensive guide on configuring iframes for this purpose, please refer to the following documentation: [rrweb Cross-Origin Iframes Setup](https://github.com/rrweb-io/rrweb/blob/master/docs/recipes/cross-origin-iframes.md).

## Privacy

Replays always mask password fields and, from JavaScript SDK 18.1.1, fields whose `autocomplete` attribute contains `current-password`, `new-password`, `one-time-code`, `cc-number` or `cc-csc`; options cannot turn this off. Other form values stay visible for debugging. You can flag other fields or even complete blocks to be masked, or set `maskAllInputs: true` to mask every input. Screenshots follow the same rules, see [Privacy controls](https://gleap-developer-docs.gleap.help/en/articles/420-javascript-sdk-privacy-controls).

### Mask text fields

Add the class `rr-mask` to a field, or to an element that contains fields, and replays mask their values as well as the text inside the element. This needs JavaScript SDK 18.1.1 or later: earlier versions mask only the text, so use `maskInputOptions` or `maskAllInputs` to mask input values there. Select menus are masked only through `maskInputOptions: { select: true }` or `maskAllInputs`.

### Mask blocks

Simply add the class `rr-block` to the elements you want to block. Replays will add a blank placeholder with the dimensions of the blocked element. This is especially handy to mask privacy sensitive blocks.

#### Mask input options

Set a kind to `true` to mask all fields of that kind. From JavaScript SDK 18.1.1, the object adds to the automatic masking: password fields stay masked even if you pass `{ password: false }` or leave `password` out. Earlier versions replace the default with your object, so include `password: true` there.

```typescript
export type MaskInputOptions = Partial<{
  color: boolean,
  date: boolean,
  "datetime-local": boolean,
  email: boolean,
  month: boolean,
  number: boolean,
  range: boolean,
  search: boolean,
  tel: boolean,
  text: boolean,
  time: boolean,
  url: boolean,
  week: boolean,
  // unify textarea and select element with text input
  textarea: boolean,
  select: boolean,
  password: boolean,
}>;
```

## Related

- [JavaScript SDK setup](https://docs.gleap.ai/en/articles/393-javascript-sdk-setup.md)
- [JavaScript SDK: Code snippet](https://docs.gleap.ai/en/articles/394-javascript-sdk-code-snippet.md)
- [JavaScript SDK: User identity](https://docs.gleap.ai/en/articles/395-javascript-sdk-user-identity.md)
- [JavaScript SDK: Callbacks](https://docs.gleap.ai/en/articles/396-javascript-sdk-callbacks.md)
- [JavaScript SDK: AI chatbar](https://docs.gleap.ai/en/articles/397-javascript-sdk-ai-chatbar.md)
