UI Monitor Privacy

UI Monitor records real visitor sessions, so protecting what does and doesn't end up in that recording matters. This page covers what's protected automatically, how to add your own rules, and the extra precautions taken so a protected element can't leak through some other path.

Always protected, automatically

On every project, with nothing to configure: password fields, and anything that looks like a payment card number/CVV or a Social Security Number (matched by standard autocomplete values and common field name/id patterns). This applies before you've touched any privacy setting at all, and it can't be turned off.

Password is a special case worth understanding. It's the one built-in protection that redacts a field's value while leaving the field itself visible in replay, shown as **** rather than hidden entirely. It's enforced at a lower level specific to password fields — none of the rule types below can replicate that same in-place redaction for any other field.

Your own rules

Configured on the Capture tab: a list of rules, each a CSS selector, a type (Block / Ignore / Mask), and a comment for your own reference. These apply on top of the built-in protections above, not instead of them.

  • Block removes the element from the recording entirely — it shows as blank/absent in replay. Use this to protect an input field's value: a date-of-birth field, a custom PII input specific to your app, anything the built-in protections don't already cover.
  • Ignore still renders the element, but interactions with it aren't recorded.
  • Mask redacts visible text content (paragraphs, headings, labels). It can't redact an input field's typed value; use Block for that instead, since masking and blocking work through genuinely different mechanisms, not two settings on the same one.

You can also apply the same protection directly in your own page markup, using the litmus-block, litmus-ignore, and litmus-mask classes, instead of (or alongside) the rule list. This is useful for elements you'd rather mark up once in your own code than maintain as a separate selector rule.

Setting up a rule: worked examples

Protecting a custom PII field. Say your account settings page has a date-of-birth input the built-in protections don't cover:

Type: Block
Selector: input[name="date_of_birth"]
Comment: DOB is PII, not covered by the built-in card/SSN/password rules

Redacting sensitive text that isn't an input. A support view might render a customer's shipping address as plain text, not a form field:

Type: Mask
Selector: .shipping-address
Comment: Customer address, visible as static text on the order detail view

Keeping a third-party widget out of the recording entirely. A chat widget or embedded iframe you don't control, and don't want captured:

Type: Ignore
Selector: #support-chat-widget
Comment: Third-party widget, interactions inside it aren't ours to record

A rule's selector is matched the same way a browser's own querySelector would match it. If a selector doesn't match anything on a given page, that rule simply doesn't apply there. An invalid selector is skipped, not an error.

Network capture (correlated API traffic)

Everything above is about the session recording (the page itself, as replayed). If a UI Monitor is also correlated with one or more API Monitors (see Monitors), it captures a second, separate stream: the actual fetch/XHR calls a matched page made, so they can be checked against real traffic instead of a synthetic response. This has its own, stricter privacy posture from the DOM recording above.

Body fields: capture-everything-except-denylisted. A captured request/response body is transmitted as-is by default. Add field names to the network capture denylist (on the Capture tab) to redact them at any depth, wherever they appear in the JSON — a password, an SSN, an internal id you don't want leaving the browser. Same matching convention as a Block/Mask rule above, but for JSON field names instead of CSS selectors.

Headers: capture-nothing-except-what-you-actually-use. Headers are treated far more conservatively than the body, since they're exactly where bearer tokens and session cookies live. Nothing is captured from a request or response's headers by default — not even with the denylist empty. There's also no separate allowlist to configure: which headers get captured is inferred automatically from your suite's own step config, specifically any Extract set to pull from Request Headers / Response Headers (see JMESPath for how a header's Extract path works). Add an Extract that reads authorization and it starts being captured on the very next session; remove the Extract and it stops, with nothing left over to clean up. The network capture denylist above still applies on top, as a hard override — a header your suite reads but you never want to leave the browser can still be excluded explicitly.

Extra precautions

  • The built-in floor can't be edited or disabled. Card/SSN/password protection is merged in at the point capture actually starts, not stored as an editable rule — so it can't be accidentally weakened or removed by a client-side bug or a mistaken edit to your own rule list.
  • Apply your own rules before capture starts. Nothing is scrubbed retroactively; a rule only protects the elements present from the moment recording begins. Review what's on any page before adding the snippet to it, especially if that page renders sensitive content before your rule's selector would even exist in the DOM.
  • Derived screenshots stay redacted too. UI Monitor checks and the Graph tab generate screenshots from a session's replay, after the fact. Those screenshots show the same redaction the live recording did — a blocked element appears hatched/blank, masked text appears blurred with a solid bar over it — so a protected element never becomes visible some other way, even in a screenshot generated well after the original session.
  • Ignored User Agent traffic isn't a privacy control. Excluding LitmusLab's own test-runner traffic (or your own added patterns) keeps that traffic out of your live-traffic signal, but it's a separate setting from anything on this page — see the Capture tab's own help for that.

Related