Privacy and Masking
Session Replay masks text and form inputs by default. Configure blocking and selector overrides for additional control.
Session Replay masks visible text and every form input by default. It also does not record <script> contents verbatim or capture <canvas> content. Use blocking and path scoping to further control what is captured.
| Behavior | What appears in replay |
|---|---|
| Mask | Asterisks replace text; element structure is intact |
| Block | Blank placeholder box; no content captured, position preserved |
| Unmask | Real text. This is an explicit opt-in for that element |
Default masking
| Surface | Default behavior | Configurable? |
|---|---|---|
<input> / <textarea> / <select> values | Always masked | Not currently |
| Page text (paragraphs, headings, links, buttons, labels) | Masked | Yes, use the unmask controls below for specific elements |
<script> text | Not recorded verbatim | No |
<canvas> content | Not captured | No (canvas capture is not currently supported) |
Layer 1: Global text masking
Visible page text is masked by default. Set mask_all_text: true when you want to add global selector masking explicitly.
ours('init', '{cdp_token}', {
session_replay: {
token: 'replay_token',
mask_all_text: true,
},
});Replay still records the page's structure (layout, scroll position, mouse trails, and click locations) while text remains masked. Use op-session-replay-ignore only for the specific text you want to make visible.
What the masked text looks like
Text masking preserves whitespace and punctuation and replaces letters and numbers with *.
| Original | Masked |
|---|---|
Hello World | ***** ***** |
Order #1234! | ***** #****! |
you@example.com | ***@*******.*** |
日本語テキスト | ******* |
Whitespace and punctuation are preserved so the page layout stays stable in the replay.
Layer 2: CSS classes
Add these classes to specific elements throughout your application. They work with or without mask_all_text.
<!-- Replace element with a placeholder box -->
<div class="op-session-replay-block">Sensitive content</div>
<!-- Bypass masking — text captured unredacted -->
<div class="op-session-replay-ignore">Non-essential content</div>
<!-- Mask text content -->
<div class="op-session-replay-mask">Sensitive text</div>| Class | Behavior |
|---|---|
op-session-replay-block | Element is replaced with a placeholder box. No children, text, or inner HTML is captured, but the element's position and dimensions are preserved in replay |
op-session-replay-ignore | Element is captured with full structure and text: masking is bypassed. Text appears unredacted even when mask_all_text: true is active. This does not unmask form control values; <input>, <textarea>, and <select> values remain masked |
op-session-replay-mask | Element's text is masked; structure is captured |
When to use which
- Block PII/PHI containers, payment forms, password fields you can't otherwise reach, and any third-party iframe whose content you don't control
- Unmask (
op-session-replay-ignore) only non-sensitive elements you need legible in the replay, such as stable UI labels - Mask elements that may contain personal data but whose structure matters for analysis (for example, search results or customer names in an admin UI)
You can use mask_all_text: true with op-session-replay-ignore to carve out only the elements that should stay legible.
Layer 3: Selector overrides
When you can't add classes (third-party widgets, headless CMS output, code you don't own), pass CSS selectors directly.
ours('init', '{cdp_token}', {
session_replay: {
token: 'replay_token',
block_selector: '.cc-card, [data-private]',
ignore_selector: '.cc-noise',
mask_text_selector: '.cc-pii',
},
});| Option | Equivalent class | Notes |
|---|---|---|
block_selector | op-session-replay-block | Any standard CSS selector; comma-separated lists are supported |
ignore_selector | op-session-replay-ignore | Unmasks matching elements. This does not unmask form control values; <input>, <textarea>, and <select> values remain masked |
mask_text_selector | op-session-replay-mask | Masks text inside matching elements |
You can also enable mask_all_text: true and use ignore_selector to selectively reveal only the elements that need to stay visible.
Picking a strategy
| If you... | Start with |
|---|---|
| Have HIPAA / PHI exposure | Default masking + block_selector for any container that holds sensitive information you must exclude entirely (forms, image-based sensitive information, third-party widgets) |
| Have PII in some pages but not most | Default masking + block_selector on the affected pages as needed |
| Run a heavily third-party-script-driven page | Default masking + block_selector for every embed you do not control |
| Need to verify what's captured | Run a session, open it in the dashboard, and review before going live with new pages |
Next steps
- Configuration: full options reference
- FAQs
How is this guide?

