Clarity Session Replay: See Why Users Drop Off — After You Get Masking Right
Clarity's session replay shows you the DOM-level reason users abandon a form — but on pages with sensitive inputs, masking is the real engineering decision. Here's how to enable, mask, and verify it before production.
26 Feb 2026, 10:48 UTC

Analytics tells you where users quit; replay tells you why
Funnels are good at exactly one thing: proving that something is wrong. If 40% of sessions die on the shipping step of your checkout, the funnel will not tell you whether the address autocomplete is covering the Continue button, whether a validation error flashes and disappears, or whether the page simply hangs on older devices. Support tickets rarely help either — users describe symptoms, not DOM state.
Microsoft Clarity's session replay is built to close that gap. The snippet records what actually happened in the browser — DOM changes, mouse movement, clicks, scrolls — and reconstructs it in the Clarity portal so you can play a session back like a video. It is free, and basic recording needs no configuration beyond pasting a script tag. So the real engineering decision is not whether to enable it. It is what you mask before you enable it, because on a page with a card number field, replay will happily record whatever the DOM contains unless you tell it not to.
What replay actually records — and why that shapes the privacy question
Clarity is not a screen recorder. The snippet instruments the page and serializes interactions into lightweight JSON events — clicks, scrolls, and DOM mutations — which are posted to www.clarity.ms and rebuilt in the portal as a synchronized replay. That design is why replay works on dynamic single-page apps and why a session costs far less bandwidth than a video would.
It is also why masking matters. Anything rendered as text in the DOM during a session can end up in the event stream. Password inputs are masked by default, but a card number typed into a plain type="text" input is not — unless you mask it explicitly.
The standard snippet, placed in your page's <head>, looks like this (replace YOUR_PROJECT_ID with the ID from your Clarity project settings):
<script type="text/javascript">
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "YOUR_PROJECT_ID");
</script>Worked example: a checkout form with card fields masked
Suppose you are enabling Clarity on a three-step checkout to debug payment-step drop-off. You want to see the payment step, but you must not record card numbers, CVV codes, or cardholder names. Clarity gives you a few masking mechanisms, each with a different blast radius:
| Mechanism | What it masks | Use it when |
|---|---|---|
| Default password masking | Values in input[type=password] | Always on — but protects nothing if your sensitive field is a text input |
data-clarity-mask attribute | Text content of that element (and its children) | Specific fields: card number, CVV, cardholder name |
| Project-level "mask all text" setting | All text across the project | Regulated data everywhere — at a high diagnostic cost |
data-clarity-unmask attribute | Re-enables text for one element under global masking | You need a single label or price visible |
For the checkout case, mask narrowly and per element:
<input type="text" name="cardNumber" data-clarity-mask autocomplete="cc-number">
<input type="text" name="cardCvv" data-clarity-mask inputmode="numeric">
<input type="text" name="cardholderName" data-clarity-mask>
<!-- leave city, state, and error messages unmasked -->Then verify before you promote anything to production. Three checks, all on a staging page with fake data:
- Load the page, interact with the form, and confirm a new session appears in the Clarity dashboard with a replay available (typically within minutes).
- Open your browser's developer tools, filter the network tab for
www.clarity.ms, and confirm POST requests carry JSON payloads containing event types such asclick,scroll, andmutation. - Replay the session and confirm the masked fields render as asterisks (or are omitted) while the fields you deliberately left visible — city, error messages — are still readable.
You need no special permissions beyond the ability to edit your markup and access to the Clarity project. Do not rely on the default masking alone: many payment forms use type="text" for card fields to avoid input-mode quirks, and the default protects none of those.
Trade-offs and limits to plan around
- Over-masking destroys the diagnostic value. If you flip on project-wide text masking, you can no longer read the validation message or the price the user saw — the two things you enabled replay for. Mask per element, not per site, unless regulation forces the broader setting.
- Masking rules are easy to get wrong in both directions. An attribute on a wrapper element masks too much and hides the form layout; a missing attribute exposes data. The only reliable test is recording and replaying a real session — not reading the docs.
- Canvas and WebGL content does not replay well. Replay reconstructs the DOM, so pages whose meaningful content lives in a canvas produce heavy sessions with little visual value.
- Retention is finite. Clarity keeps replay data for a limited window — commonly cited around 90 days at the time of writing; confirm the current figure in your project settings or the docs. If you need long-term archives, plan on exporting sessions via the Clarity API.
- Consent requirements still apply. If you operate where tracking needs user consent, Clarity exposes a consent API (
clarity("consent")) you can wire into your cookie-banner flow.
Rollout checklist
- Paste the snippet on a staging page only.
- Add
data-clarity-maskto every sensitive input, not just password fields. - Record one session and replay it: confirm masking works and unmasked context is still useful.
- Inspect the network payloads to
www.clarity.msso you know what is actually leaving the browser. - Ship to production, and re-verify masking after any markup refactor that renames or moves fields — a renamed input silently loses its attribute.
The pattern to internalize: replay is cheap to turn on and impossible to undo retroactively. You cannot un-record a session that captured a card number. Spend the extra hour getting masking right first, and session replay becomes what it is best at — the tool that finally shows you the why behind your funnel.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.