Consenti

Microsoft Clarity

Clarity records sessions and builds heatmaps — squarely analytics-purpose tracking, and squarely something you shouldn't start before consent. Consenti gives you a Clarity-shaped consent object plus the primitives to gate the tracking script itself and keep Clarity's own runtime consent flag in sync.

Reading consent in Clarity's shape

typescript
const clarityConsent = widget.getConsent('microsoft-clarity')
// {
//   session: 'granted',      // session recordings
//   heatmaps: 'granted',     // click/scroll heatmaps
//   performance: 'granted',  // performance/rage-click metrics
// }
ℹ️All three keys currently roll up from the same analyticspurpose — Clarity doesn't offer a way to separately opt out of, say, heatmaps but not session recording. See API Methods for the full getConsent(type) reference.

Step 1 — Gate the tracking script

Clarity has no build-time way to defer its own start, so the reliable approach is to not load clarity.js at all until consent exists. Wrap the standard snippet in a CategoryScript, keyed to your own authored category ID (see Category type) — 'analytics' below is the common convention:

clarity.ts
typescript
import { CategoryScript } from '@consenti/ui'

new CategoryScript({
  categoryId: 'analytics',
  widget,
  unsafeInnerHTML: `
    (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");
  `,
  onLoad: () => console.log('Clarity loaded'),
  onRevoke: () => console.log('Clarity script removed'),
})
⚠️Removing the <script> tag on revoke (which CategoryScript does automatically) stops newClarity activity, but doesn't retroactively delete anything already captured in that session before revocation — same caveat as any script-gated analytics tool. Load it only after consent in the first place if that matters for your compliance posture, rather than relying on gate-then-revoke.

Step 2 — Sync Clarity's own consent API

If your Clarity project has “require consent” behaviour configured, or you want an explicit signal independent of script presence, call clarity('consent', …) directly from a CategoryAction:

clarity-consent.ts
typescript
import { CategoryAction } from '@consenti/ui'

new CategoryAction({
  id: 'analytics',
  widget,
  onGrant: () => window.clarity?.('consent', true),
  onDeny: () => window.clarity?.('consent', false),
})

Run this alongside the CategoryScript above — the script gate controls whether Clarity is present at all, and the consent call controls its behaviour once it is.

Verifying

  1. Before consenting, open Network tab and confirm no request to clarity.ms/tag/… or clarity.ms/collect fires.
  2. Accept the analytics category on the Consenti banner.
  3. Confirm the Clarity script now loads, and check the Clarity dashboard — new sessions should appear within a couple of minutes (Clarity batches uploads, so it isn't instant).

Frequently asked questions