Real Issues, Honest Comparison & Step-by-Step Setup
We didn’t plan to switch. Like many SaaS teams, we had been using Hotjar for years, heatmaps, session recordings, the works. It was familiar, it mostly worked, and it lived in our stack the way old furniture does: unremarkable but present.
Then things started breaking. Not catastrophically, not all at once, but in the slow, maddening way that forces you to question whether the tool is working for you or you’re working around the tool.
This post is the honest story of what broke, what we tried to fix, why we eventually migrated to Microsoft Clarity, and exactly how we set it up. No sponsorship, no affiliate links, just a real migration log.
One important caveat before we dive in: these issues aren’t universal, Hotjar works well for many teams and remains a solid tool for marketing sites and simpler setups. But if your stack looks like ours (React SPA, CSS-in-JS design system, complex multi-step forms), these are the specific friction points we hit. Your mileage may vary.
1. What Broke: The Real Problems We Hit with Hotjar
Masking Gone Wrong
Hotjar’s data masking, the mechanism that suppresses sensitive form inputs in session recordings, started causing us grief in two distinct ways.
First, aggressive over-masking. Hotjar’s default behaviour masks virtually everything on a form page. That’s fine for a login screen, but we had complex multi-step onboarding flows where we needed to see how users interacted with non-sensitive fields like dropdown selectors and radio buttons. Every relevant interaction was a blurry rectangle.
We tried to configure suppression exclusions, the documented way to tell Hotjar “don’t mask this element.” The syntax is fiddly, class-name dependent, and had to be updated every time our design system renamed a component. One front-end deploy could silently wipe out weeks of recording data because a CSS class changed.
Second, and in our case worse: under-masking on elements we hadn’t anticipated. Hotjar’s masking is opt-in by the developer, if you miss an element, it records. An autocomplete component that pulled in user email addresses was sometimes captured in plain text in older snapshots. This isn’t a Hotjar bug per se; it’s a consequence of the manual-configuration model. But we caught it in an internal audit, and the discovery made us distrust our setup fundamentally.
Key Insight
Data masking is not a “set it and forget it” feature. Every UI change is a potential compliance gap if your masking config is tied to CSS selectors rather than semantic roles.
Session Replay Issues
Session replay quality degraded noticeably when our application moved to a React-based SPA architecture. We saw three recurring problems:
- Blank or white screens mid-replay, the recording would start, show a spinner, then go white for 20–40 seconds before resuming. Useless for diagnosing drop-offs.
- Clicks registered in the wrong coordinates, likely a viewport-scaling or dynamic layout issue. We’d see rage clicks on empty space where a CTA button used to be before a layout shift.
- Network-throttled replays dropped frames, users on slow connections had replays that looked fine on our end but we couldn’t tell where exactly they gave up.

2. The Knock-On Effect: How These Issues Hurt UX Debugging
The issues above weren’t just annoying, they degraded our ability to make good product decisions.
When session replays go blank or show wrong click coordinates, your instinct is to distrust all the data. We found ourselves mentally discounting recordings, saying things like “the replay shows rage clicks here, but let’s not trust that.” You can’t build a feedback loop when you don’t trust your instruments.
The masking issues were even more corrosive. Our UX team had a standing rule: “don’t watch replays of the billing page” because of the occasional unmasked data risk. So an entire section of our funnel, the most commercially important one, became a recording dead zone.
Without reliable visibility into those flows, we were shipping UX changes based on gut feel and aggregate metrics alone. Conversion rates moved, and we had no way to watch why.
3. Head-to-Head: Hotjar vs. Microsoft Clarity
Before committing to Clarity, we did a structured evaluation. Here’s how they compare on the dimensions that mattered to us:
| Feature | Hotjar | Microsoft Clarity |
| Pricing | From $39/month (paid plans) | Free (up to 25K sessions/day) |
| Session Replay | Yes | Yes |
| Heatmaps | Yes (click, scroll, move) | Yes (click, scroll) |
| Data Masking | Manual setup required | Auto-masking by default |
| GDPR Compliance | Requires configuration | Built-in, easier setup |
| Funnel Analysis | Yes | Limited |
| Rage Click Detection | Yes | Yes |
| JS Error Tracking | No | Yes |
| Integrations | Many (GA, Segment, etc.) | Native Microsoft & Power BI |
| Setup Complexity | Moderate | Very easy (tag-based) |
| Support | Email + chat | Microsoft docs + community |
Our Honest Assessment
Hotjar is a mature, feature-rich platform, it still wins on funnel analysis, form analytics, and third-party integrations. If you’re running a marketing site and need to stitch Hotjar into a Segment + Mixpanel + GA stack, it’s still a strong choice.
Clarity wins hard on three things: cost (free at meaningful scale), automatic masking that doesn’t require CSS selector babysitting, and JavaScript error tracking baked directly into the replay timeline. That last feature alone would have saved us two weeks of debugging last year.
Clarity’s integration with the Microsoft ecosystem is a bonus if you’re already in Azure or Power BI, but it wasn’t a deciding factor for us. We’re not a Microsoft shop.
4. Setting Up Microsoft Clarity (Step-by-Step)
Clarity’s setup is genuinely fast. Here’s exactly what we did.
Step 1: Create a Project
Go to clarity.microsoft.com and sign in with a Microsoft account. Click “New project”, give it a name, and enter your website URL. Clarity will generate a unique Project ID (e.g., abc123xyz) that you’ll need in the next step.
Step 2: Install the Tracking Script
Add the Clarity snippet to the <head> of every page. For a standard HTML site:
<!-- Microsoft Clarity Tracking Script -->
<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>
Replace YOUR_PROJECT_ID with the ID from your Clarity dashboard.
Step 3: React / Next.js Integration
If you’re on a React or Next.js app, the cleanest approach is to install the official package and initialize it in your app entry point:
# Install the package
npm install @microsoft/clarity
# Or with yarn
yarn add @microsoft/clarity
Then initialize in your app root (e.g., _app.tsx in Next.js or index.tsx in CRA):
import Clarity from '@microsoft/clarity';
// Initialise once when the app loads
// Place this in your root component or useEffect
Clarity.init('YOUR_PROJECT_ID');
Step 4: Custom Event Tracking
Clarity lets you tag key interactions with custom events for segmented replay filtering. This is especially useful for tracking high-value actions like sign-ups, purchases, or feature engagement.
Basic custom event:
// Fire a custom event with a key-value pair
// clarity('set', key, value)
// Track when a user starts the onboarding flow
clarity('set', 'onboarding_started', 'true');
// Tag sessions by user plan for segmentation
clarity('set', 'user_plan', 'pro');
// Track a specific funnel step
clarity('set', 'checkout_step', '3_payment');
React hook pattern for event tracking:
import { useEffect } from 'react';
function useClarityEvent(key: string, value: string) {
useEffect(() => {
if (typeof window !== 'undefined' && window.clarity) {
window.clarity('set', key, value);
}
}, [key, value]);
}
// Usage in a component
function PricingPage() {
useClarityEvent('page_view', 'pricing');
useClarityEvent('user_intent', 'upgrade');
// ... rest of component
}
Identify logged-in users (for user-level session stitching):
// After user authentication — link sessions to your user ID
// clarity('identify', userId, sessionId?, pageId?, friendlyName?)
clarity('identify', 'user_abc123', null, null, 'Jane Doe');
// In a React auth context:
useEffect(() => {
if (user && window.clarity) {
clarity('identify', user.id, undefined, undefined, user.name);
}
}, [user]);
Pro Tip
Use custom events to tag sessions by subscription plan, A/B test variant, or onboarding step. You can then filter replays in the Clarity dashboard to only watch sessions matching specific conditions, dramatically reducing noise.
Step 5: Verify Installation
Open your site in a browser, navigate around for 30 seconds, then return to the Clarity dashboard. Under “Setup” you should see a green “Data received” status within a few minutes. Full session replays typically appear within 2 hours.
You can also use the browser console to verify Clarity is loaded:
// In browser DevTools console
window.clarity
// Should return: ƒ clarity() — confirming the tag is active
5. One Month In: What We’ve Noticed
We’ve now been running Clarity alongside (and slowly replacing) Hotjar for about a month. A few honest observations:
- Masking is noticeably more reliable. The automatic PII masking works at the DOM attribute level rather than CSS selectors, which means it survives component renames. We’ve had zero accidental data captures in our billing section.
- JavaScript error overlays in replays are a game-changer. We can watch a session, see exactly when a JS error fired, and cross-reference it with the user’s actions. We’ve already squashed three silent bugs we didn’t know existed.
- The free tier is real. We’re at about 18,000 sessions/day and haven’t been asked to upgrade. That’s a meaningful budget saving.
- Funnel analysis is where Clarity falls short. We still use a lightweight Hotjar plan for our marketing site where funnel metrics matter more. For the app itself, Clarity is sufficient.
- Rage click data is more actionable. Clarity’s rage click identification seems more accurate, fewer false positives from rapid legitimate clicks on animated elements.

Final Thoughts
Switching analytics tools is a commitment, not just technically, but organizationally. People have learned workflows, built dashboards, and developed intuitions. We didn’t move fast.
But the masking reliability and the zero cost made the migration worthwhile for our core product. If you’re hitting similar issues, broken replays on SPAs, masking config that breaks with every deploy, or a Hotjar bill that’s harder to justify as you scale, Clarity is worth a serious evaluation.
The setup is genuinely simple. The automatic masking reduces compliance risk. And free at 25,000 sessions/day removes a recurring line from your SaaS spend.
If you’re still on the fence: spin up a Clarity project, install the tag alongside Hotjar, and let both run for two weeks. The data will make the decision for you.
You may also like: How AI Will Transform Customer Support in the Next 5 Years
