Mask Sensitive UI Data in Code Before Enabling Clarity Session Recordings
Clarity snapshots the DOM, so plain-text account numbers and health data can leak into replays. Add element-level masking in your front-end code and verify in staging before opening access.
08 Oct 2025, 14:36 UTC

The leak isn't in the video—it's in the DOM
If your team is about to switch on Microsoft Clarity session recordings, the first question should not be "Which pages do we record?" but "What will those replays expose?" Clarity does not capture a video of the screen; it snapshots the DOM. That distinction matters because any text rendered into the page—account numbers, tokens, health data—becomes part of the replay unless you explicitly mask it. The useful takeaway: add element-level masking in your front-end code before you grant dashboard access, and verify the result in a staging project.
Default masking covers inputs, not your custom components
By default, Clarity masks standard input fields. That makes sense because inputs often hold passwords or personal details. However, Clarity does not automatically redact sensitive values rendered as plain text, table cells, or inside third-party widgets. A span that displays a customer's account balance, a table row with a policy number, or an embedded support chat widget can all leak into the replay. Treating masking as a front-end code review concern—rather than a post-processing step—keeps the decision close to the component that renders the data.
Worked example: masking an account-number table
Suppose you have a billing table that renders account numbers as plain text. Before masking, the value is fully visible in the replay:
<!-- Before: plain text is captured in the DOM snapshot -->
<td class="account-cell">ACCT-88291003</td>Apply the masking attribute supported by your Clarity snippet to the element that renders the value. The exact attribute name is version-sensitive; confirm the current property in the Clarity documentation for your project version. A common pattern looks like this:
<!-- After: apply the masking attribute to the value container -->
<td class="account-cell" data-clarity-mask="true">ACCT-88291003</td>To find other components that need the same treatment, run a targeted search from your repository root:
# Run in the front-end repository root
grep -rn "accountNumber" src/ --include="*.jsx" --include="*.tsx" --include="*.vue" --include="*.html"Expected check: the command returns files that render sensitive fields. Review each match and decide whether the masking attribute belongs on the value element or its immediate wrapper. Risk: grep will miss values stored under different variable names or constructed dynamically from API responses, so pair the search with a manual review of components that fetch customer data.
After deploying the change, open the page in a browser, inspect the element in DevTools, and confirm the attribute is present in the live DOM before you record a session. If a masked element blocks debugging, remove the attribute and redeploy—that is the rollback for this state change.
Project-level controls help, but they don't replace element masking
Clarity offers project-level controls such as IP address masking and data retention limits. These reduce metadata exposure and shorten the window in which replays remain available. They are useful complements, but they do not redact sensitive text that has already been captured in a DOM snapshot. Element-level masking is the only mechanism that prevents the value from entering the recording in the first place.
The observability-privacy trade-off
Aggressive masking hides the context needed to debug layout or state issues. If you mask an entire table row, a reviewer cannot see whether the row rendered correctly or whether a column was misaligned. Minimal masking increases compliance exposure in regulated environments. A practical middle ground is to mask only the sensitive value cell while leaving headers, labels, and structural elements visible. That preserves enough context to diagnose rendering bugs without exposing the underlying data.
Limitations and version sensitivity
Client-side masking is not a security boundary. It prevents casual exposure in the dashboard, but it cannot stop a malicious user from altering the page before data is sent. Single-page applications and iframes can also complicate masking because dynamic content mounts after the initial page load. Verify that masking rules apply to late-rendered nodes, especially in modal dialogs or lazy-loaded widgets. Because exact attribute names, consent APIs, and dashboard filtering options are version-sensitive, confirm current behavior in a staging project before rolling out broadly.
A practical rollout checklist
- Create a staging page that renders known fake values—for example, a fake account number and email—in the same components used in production.
- Apply the masking attribute to the elements that render those values, then deploy to staging.
- Record a short session as a single internal user and play it back in Clarity to confirm the values are obscured.
- Use Clarity's dashboard filters or custom event tags to isolate the test session so reviewers do not have to search through unrelated traffic.
- Inspect the replay for unmasked PII in tables, plain-text nodes, and third-party widgets; iterate on masking rules before opening access to the wider team.
Masking is a small code change with a large compliance impact. Making it a review gate—rather than an afterthought—lets your team debug UI issues with session recordings without turning every replay into a privacy incident.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.