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

# Privacy Controls

> Block, mask, or ignore elements to control what Milana records in session replays.

Milana gives you granular control over what is and is not captured in session recordings. There are three mechanisms:

* **Block** — the element is replaced with a blank placeholder in the recording. Its contents are never sent to Milana.
* **Mask** — the element's text or input value is replaced with masked placeholders. The element's structure stays visible, but its text and input values are not.
* **Ignore** — user interactions on the element (clicks, inputs) are not recorded, but the element's content is still visible in the replay.

Masking applies to text and form input values only — it does not mask HTML attribute values such as `alt`, `title`, `href`, and `src`.

<Note>
  Passwords (`input[type="password"]`), phone numbers (`input[type="tel"]`), and email addresses (`input[type="email"]`) are always masked and cannot be revealed.
</Note>

## Default CSS classes

The easiest way to apply privacy controls is to add a CSS class to the element in your HTML or JSX. The SDK respects these classes out of the box, with no additional configuration required.

| Class           | Effect                                                                                           |
| --------------- | ------------------------------------------------------------------------------------------------ |
| `milana-block`  | Element is blocked — replaced with a placeholder, contents not recorded                          |
| `milana-mask`   | Text content and input values are replaced with masked placeholders                              |
| `milana-unmask` | Reveals matching elements at `high` or `xhigh`, unless another privacy rule masks or blocks them |
| `milana-ignore` | User interactions on the element are not recorded                                                |

### Block an element

```html theme={null}
<!-- The entire card, including all child content, will not be recorded -->
<div class="billing-card milana-block">
  <span>Card ending in 4242</span>
</div>
```

### Mask text content

```html theme={null}
<!-- The user's full name is captured as masked placeholders -->
<p class="milana-mask">Jonathan Appleseed</p>
```

### Mask an input

```html theme={null}
<!-- The value typed into this field is masked regardless of input type -->
<input type="text" class="milana-mask" placeholder="National ID number" />
```

### Ignore interactions

```html theme={null}
<!-- Clicks and keystrokes on this element are not recorded -->
<textarea class="milana-ignore" placeholder="Private notes"></textarea>
```

## Custom classes and selectors

If you cannot use the default class names, configure your own via the `privacy` option when initializing.

<Tabs>
  <Tab title="React">
    ```tsx theme={null}
    <MilanaProvider
      productId="prd_..."
      clientKey="key_..."
      sessionInfo={{ environment: "production", version: "1.0.0" }}
      options={{
        privacy: {
          blockClass: "my-private",
          blockSelector: "[data-sensitive]",
          ignoreClass: "no-record",
          ignoreSelector: "[data-no-record]",
          maskTextClass: "redact-text",
          maskInputClass: "redact-input",
          maskSelector: "[data-mask]",
          unmaskClass: "record-public",
        },
      }}
    >
      <App />
    </MilanaProvider>
    ```
  </Tab>

  <Tab title="Script Tag">
    ```javascript theme={null}
    Milana("init", "prd_...", "key_...",
      { environment: "production", version: "1.0.0" },
      {
        privacy: {
          blockClass: "my-private",
          blockSelector: "[data-sensitive]",
          ignoreClass: "no-record",
          ignoreSelector: "[data-no-record]",
          maskTextClass: "redact-text",
          maskInputClass: "redact-input",
          maskSelector: "[data-mask]",
          unmaskClass: "record-public",
        },
      }
    );
    ```
  </Tab>
</Tabs>

<Note>
  The selector-based options (`blockSelector`, `ignoreSelector`, `maskSelector`, `unmaskSelector`) are matched against elements while the page is being recorded. Complex selectors can affect page performance — prefer simple, specific selectors.
</Note>

## Full example

<Tabs>
  <Tab title="React">
    ```tsx theme={null}
    <MilanaProvider
      productId="prd_..."
      clientKey="key_..."
      sessionInfo={{ environment: "production", version: "1.0.0" }}
      options={{
        privacy: {
          blockClass: "milana-block",
          blockSelector: "#stripe-elements, [data-payment-form]",
          maskTextClass: "milana-mask",
          maskInputClass: "milana-mask",
          maskInputTypes: {
            password: true,
            tel: true,
          },
          shouldTrackQueryParams: true,
          queryTrackingParamsDenyList: [/^invite$/i, /^signup_token$/i],
        },
      }}
    >
      <App />
    </MilanaProvider>
    ```
  </Tab>

  <Tab title="Script Tag">
    ```javascript theme={null}
    Milana("init", "prd_...", "key_...",
      { environment: "production", version: "1.0.0" },
      {
        privacy: {
          blockClass: "milana-block",
          blockSelector: "#stripe-elements, [data-payment-form]",
          maskTextClass: "milana-mask",
          maskInputClass: "milana-mask",
          maskInputTypes: {
            password: true,
            tel: true,
          },
          shouldTrackQueryParams: true,
          queryTrackingParamsDenyList: [/^invite$/i, /^signup_token$/i],
        },
      }
    );
    ```
  </Tab>
</Tabs>

For the full list of privacy options and their defaults, see the [Privacy Options Reference](/sdk/privacy).

## Masking levels

The controls above mask individual elements. If you would rather mask everything by default and reveal only the elements you trust, raise the `maskingLevel`.

| Level              | Input values                       | DOM text                           |
| ------------------ | ---------------------------------- | ---------------------------------- |
| `normal` (default) | Masked only when explicitly marked | Masked only when explicitly marked |
| `high`             | All masked                         | Masked only when explicitly marked |
| `xhigh`            | All masked                         | All masked                         |

<Tabs>
  <Tab title="React">
    ```tsx theme={null}
    <MilanaProvider
      productId="prd_..."
      clientKey="key_..."
      sessionInfo={{ environment: "production", version: "1.0.0" }}
      options={{
        privacy: {
          maskingLevel: "xhigh",
        },
      }}
    >
      <App />
    </MilanaProvider>
    ```
  </Tab>

  <Tab title="Script Tag">
    ```javascript theme={null}
    Milana("init", "prd_...", "key_...",
      { environment: "production", version: "1.0.0" },
      {
        privacy: {
          maskingLevel: "xhigh",
        },
      }
    );
    ```
  </Tab>
</Tabs>

### Reveal trusted elements

At `high` or `xhigh`, add the `milana-unmask` class or use `unmaskSelector` to reveal elements that are safe to record — navigation, buttons, headings, translated product copy, and other non-sensitive UI:

<Tabs>
  <Tab title="React">
    ```html theme={null}
    <nav class="milana-unmask">...</nav>
    ```

    ```tsx theme={null}
    <MilanaProvider
      productId="prd_..."
      clientKey="key_..."
      sessionInfo={{ environment: "production", version: "1.0.0" }}
      options={{
        privacy: {
          maskingLevel: "xhigh",
          unmaskSelector: "nav, h1, h2, h3, [data-public]",
        },
      }}
    >
      <App />
    </MilanaProvider>
    ```
  </Tab>

  <Tab title="Script Tag">
    ```html theme={null}
    <nav class="milana-unmask">...</nav>
    ```

    ```javascript theme={null}
    Milana("init", "prd_...", "key_...",
      { environment: "production", version: "1.0.0" },
      {
        privacy: {
          maskingLevel: "xhigh",
          unmaskSelector: "nav, h1, h2, h3, [data-public]",
        },
      }
    );
    ```
  </Tab>
</Tabs>

`milana-unmask`, `unmaskClass`, and `unmaskSelector` only reveal what the masking level masked. They never override an explicit mask (`milana-mask`, `maskSelector`), a blocked element (`milana-block`, `blockSelector`), or an always-masked input type (`password`, `tel`, `email`). Those stay masked no matter what.

If you set a custom `unmaskClass`, it replaces the default `milana-unmask` class. Set `unmaskClass` to an empty string (`""`) to disable class-based unmasking.

## Layout-preserving masking

By default, masking is implemented by replacing each character with `*`. Enable `shouldUseLayoutPreservingMasking` to replace masked text with width-matched placeholders that keep replays closer to the page's original layout.

It is recommended to enable this for applications that mask long text, especially when using `high` or `xhigh` masking.

<Tabs>
  <Tab title="React">
    ```tsx theme={null}
    <MilanaProvider
      productId="prd_..."
      clientKey="key_..."
      sessionInfo={{ environment: "production", version: "1.0.0" }}
      options={{
        privacy: {
          shouldUseLayoutPreservingMasking: true,
        },
      }}
    >
      <App />
    </MilanaProvider>
    ```
  </Tab>

  <Tab title="Script Tag">
    ```javascript theme={null}
    Milana("init", "prd_...", "key_...",
      { environment: "production", version: "1.0.0" },
      {
        privacy: {
          shouldUseLayoutPreservingMasking: true,
        },
      }
    );
    ```
  </Tab>
</Tabs>

<Note>
  Layout-preserving masking changes how masked content is rendered, not which content is masked. It may preserve approximate word widths, hyphen positions, and line breaks. Use the `milana-block` class when an element should be recorded as a blank placeholder instead.
</Note>

## iframes

Privacy controls configured in the parent page do not propagate into iframes. See the [Iframe Recording](/guides/iframe-recording) guide for setup instructions and how to apply privacy controls inside iframes.

## Data residency

For full control over where session data is stored, you can bring your own storage bucket. See the [BYO Storage](/guides/byo-storage) guide.
