Microsoft Clarity Data Layer Setup
Overview
Microsoft Clarity doesn't have a formal "data layer" concept like Google Tag Manager or Adobe Analytics. However, you can structure your data collection using Clarity's JavaScript API (clarity("set"), clarity("event"), clarity("identify")) to create a consistent, maintainable tracking architecture.
This guide shows you how to organize custom data, establish naming conventions, and build a scalable tracking plan that makes Clarity data useful and actionable.
What Is a Data Layer (In the Clarity Context)?
A data layer is a structured JavaScript object or approach that:
- Centralizes tracking logic – All tracking calls in one place, not scattered across your codebase
- Standardizes data format – Consistent naming, values, and structure
- Separates business logic from tracking – Developers can update features without breaking analytics
- Makes data actionable – Enables filtering, segmentation, and analysis in Clarity dashboard
For Clarity, a data layer strategy means using:
- Custom events (
clarity("event", "event_name")) to mark user actions - Custom tags (
clarity("set", "key", "value")) to add session metadata - User identification (
clarity("identify", "user_id")) to link sessions
Why Structure Your Clarity Data?
Without structure:
// Scattered, inconsistent tracking
clarity("event", "checkout");
clarity("event", "Checkout Complete");
clarity("event", "checkout_done");
You end up with:
- Inconsistent event names (hard to filter)
- No context (which product? which user?)
- No reusable patterns
With structure:
// Centralized, consistent tracking
ClarityDataLayer.trackEvent("checkout_complete", {
product_id: "12345",
product_name: "Blue Widget",
price: 49.99
});
You get:
- Standardized naming
- Rich context via tags
- Easy filtering in Clarity dashboard
- Maintainable codebase
Clarity Data Layer Architecture
Core Components
- Event Taxonomy – Standardized list of events you track
- Custom Tags Schema – Key-value pairs for session metadata
- User Identification Strategy – How you identify users
- Tracking Wrapper – Centralized function to send data to Clarity
Example Structure
// ClarityDataLayer.js
const ClarityDataLayer = {
// Initialize Clarity (if not already loaded)
init: function(projectId) {
if (typeof clarity === 'undefined') {
console.warn('Clarity not loaded');
return;
}
this.ready = true;
},
// Track custom event
trackEvent: function(eventName, properties = {}) {
if (!this.ready) return;
// Set properties as custom tags
for (const [key, value] of Object.entries(properties)) {
clarity("set", key, String(value));
}
// Fire the event
clarity("event", eventName);
},
// Identify user
identifyUser: function(userId, traits = {}) {
if (!this.ready) return;
// Set user identifier
clarity("identify", userId);
// Set user traits as tags
for (const [key, value] of Object.entries(traits)) {
clarity("set", `user_${key}`, String(value));
}
},
// Set global session properties
setSessionProperty: function(key, value) {
if (!this.ready) return;
clarity("set", key, String(value));
}
};
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
ClarityDataLayer.init();
});
Implementing the Data Layer
Step 1: Define Your Event Taxonomy
Create a standard list of events your site will track.
Example Event Taxonomy:
| Event Name | Trigger | Purpose |
|---|---|---|
page_viewed |
Page load | Track virtual pageviews (SPAs) |
button_clicked |
CTA button click | Measure engagement |
form_submitted |
Form submission | Track conversions |
video_played |
Video play | Content engagement |
checkout_started |
Checkout initiated | E-commerce funnel |
checkout_complete |
Order confirmed | Purchase conversion |
signup_complete |
User registers | Lead generation |
Naming Convention:
- Use
snake_case(lowercase with underscores) - Be descriptive but concise
- Use action verbs:
clicked,viewed,submitted,completed
Step 2: Define Custom Tags Schema
Decide what metadata you'll attach to events and sessions.
Example Tags Schema:
| Tag Name | Type | Example Value | Usage |
|---|---|---|---|
user_type |
string | premium, free, trial |
Segment by plan |
product_id |
string | SKU_12345 |
E-commerce tracking |
product_category |
string | electronics |
Category analysis |
experiment_variant |
string | A, B |
A/B testing |
page_type |
string | homepage, product, checkout |
Page categorization |
Step 3: Implement Tracking Wrapper
Use the ClarityDataLayer object to centralize all tracking calls.
Basic Implementation
// Track a simple event
ClarityDataLayer.trackEvent("button_clicked");
// Track an event with context
ClarityDataLayer.trackEvent("product_viewed", {
product_id: "SKU_12345",
product_name: "Blue Widget",
product_category: "widgets",
price: 29.99
});
// Identify a user
ClarityDataLayer.identifyUser("user_abc123", {
subscription: "premium",
signup_date: "2024-01-15"
});
// Set global session property
ClarityDataLayer.setSessionProperty("experiment_variant", "B");
Real-World Examples
E-Commerce: Add to Cart
document.querySelectorAll('.add-to-cart-btn').forEach(button => {
button.addEventListener('click', function(e) {
const productId = this.dataset.productId;
const productName = this.dataset.productName;
const productPrice = this.dataset.productPrice;
ClarityDataLayer.trackEvent("add_to_cart", {
product_id: productId,
product_name: productName,
price: productPrice,
currency: "USD"
});
});
});
SaaS: Trial Signup
function onTrialSignupComplete(user) {
ClarityDataLayer.identifyUser(user.id, {
subscription: "trial",
company_size: user.companySize,
industry: user.industry
});
ClarityDataLayer.trackEvent("signup_complete", {
plan: "trial",
source: user.signupSource
});
}
Content Site: Article Read
// Track when user scrolls 75% through article
let tracked75Percent = false;
window.addEventListener('scroll', function() {
const scrollPercent = (window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100;
if (scrollPercent >= 75 && !tracked75Percent) {
tracked75Percent = true;
ClarityDataLayer.trackEvent("article_read_75", {
article_id: articleId,
article_title: articleTitle,
author: articleAuthor,
category: articleCategory
});
}
});
Step 4: Integrate with Your Application
Single Page Applications (React Example)
// utils/ClarityTracking.js
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
export function useClarityPageTracking() {
const location = useLocation();
useEffect(() => {
// Track virtual pageview on route change
ClarityDataLayer.trackEvent("page_viewed", {
page_path: location.pathname,
page_title: document.title
});
}, [location]);
}
// App.js
import { useClarityPageTracking } from './utils/ClarityTracking';
function App() {
useClarityPageTracking();
return (
<Router>
{/* Your app */}
</Router>
);
}
Vue.js Example
// plugins/clarity.js
export default {
install(Vue) {
Vue.prototype.$clarity = ClarityDataLayer;
// Track route changes
Vue.mixin({
mounted() {
if (this.$route) {
this.$clarity.trackEvent("page_viewed", {
page_path: this.$route.path,
page_title: document.title
});
}
}
});
}
};
// Use in components
this.$clarity.trackEvent("feature_used", {
feature_name: "dark_mode"
});
Advanced Patterns
Event Batching (Reduce Noise)
Avoid firing too many events for rapid interactions (e.g., scroll events):
let scrollTimeout;
window.addEventListener('scroll', function() {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
const scrollPercent = Math.round((window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100);
ClarityDataLayer.trackEvent("scroll_depth", {
scroll_percent: scrollPercent,
page: window.location.pathname
});
}, 1000); // Only fire after user stops scrolling for 1 second
});
Conditional Tracking
Only track events for certain user segments:
function trackForPremiumUsersOnly(eventName, properties) {
if (user.isPremium) {
ClarityDataLayer.trackEvent(eventName, properties);
}
}
Error Tracking
Capture JavaScript errors for debugging:
window.addEventListener('error', function(event) {
ClarityDataLayer.trackEvent("javascript_error", {
error_message: event.message,
error_source: event.filename,
error_line: event.lineno,
page: window.location.pathname
});
});
Form Tracking
Track form interactions and submissions:
const form = document.querySelector('#contact-form');
// Track form start
form.addEventListener('focusin', function(e) {
if (!form.dataset.clarityTracked) {
form.dataset.clarityTracked = 'true';
ClarityDataLayer.trackEvent("form_started", {
form_id: "contact_form"
});
}
}, { once: true });
// Track form submission
form.addEventListener('submit', function(e) {
e.preventDefault();
ClarityDataLayer.trackEvent("form_submitted", {
form_id: "contact_form",
form_fields: form.querySelectorAll('input, select, textarea').length
});
// Then actually submit form
this.submit();
});
Data Governance & Best Practices
Naming Conventions
✅ Do:
- Use
snake_casefor all event and tag names - Be consistent:
checkout_started,checkout_complete(notCheckout Start,checkout_done) - Use verbs for events:
clicked,viewed,submitted - Use nouns for tags:
product_id,user_type,page_category
❌ Don't:
- Mix naming styles:
checkoutStartedvs.checkout_complete - Use special characters or spaces
- Use generic names:
event1,tag_a
Privacy & Compliance
✅ Do:
- Hash or anonymize user IDs before calling
clarity("identify") - Avoid sending PII in event properties
- Document what data you collect and why
❌ Don't:
- Send email addresses, phone numbers, names in Clarity events or tags
- Track sensitive financial or health data
- Assume default masking catches everything (review recordings)
Documentation
Maintain a Tracking Plan document:
| Event Name | Trigger | Properties | Owner | Notes |
|---|---|---|---|---|
checkout_complete |
Order confirmation | order_id, total, currency |
Marketing | Track purchases |
feature_toggled |
User toggles setting | feature_name, enabled |
Product | A/B test analysis |
Testing
Before deploying to production:
- Test in dev environment: Fire events, check console for errors
- Verify in Clarity dashboard: Confirm events appear in filters within 30 mins
- Watch recordings: Ensure events fire at the right moments
- Check data quality: Verify tag values are correct (not
undefinedornull)
Integration with Google Tag Manager
If you use GTM, you can structure a Clarity data layer using GTM's built-in dataLayer object.
Push to GTM Data Layer
// Push Clarity events to GTM dataLayer
dataLayer.push({
'event': 'clarity_event',
'clarityEventName': 'checkout_complete',
'clarityProperties': {
'order_id': '12345',
'total': 99.99
}
});
GTM Tag Configuration
<script>
var eventName = {{clarityEventName}};
var properties = {{clarityProperties}};
if (typeof clarity !== 'undefined') {
for (var key in properties) {
clarity("set", key, String(properties[key]));
}
clarity("event", eventName);
}
</script>
- Set trigger to fire on
clarity_event
This centralizes all tracking in GTM's dataLayer while still using Clarity's API.
Troubleshooting
Events Not Appearing in Filters
Symptoms: Events fired in code but don't appear as filter options in Clarity
Causes:
- Events haven't been fired yet (Clarity only shows events that have occurred at least once)
- Typo in event name
- Clarity not loaded when event fires
Fix:
- Trigger the event on your site, wait 15-30 minutes, check again
- Verify event name spelling
- Ensure Clarity script loads before your tracking code runs
Tag Values Showing as "undefined"
Symptoms: Custom tags appear in sessions but show undefined as value
Causes:
- JavaScript variable is
undefinedwhenclarity("set")is called - Trying to pass objects instead of strings
Fix:
- Ensure variables have values before passing to
clarity("set") - Convert all values to strings:
clarity("set", "key", String(value))
Too Many Events Overwhelming Data
Symptoms: Thousands of events making Clarity session filters unusable
Causes:
- Tracking every scroll, mousemove, or frequent interaction
Fix:
- Use event batching (debounce/throttle)
- Only track meaningful interactions
- Limit events to 10-20 unique event names
Summary
Microsoft Clarity doesn't have a formal data layer, but you can build one using:
- Centralized tracking wrapper (
ClarityDataLayer) - Standardized event taxonomy
- Consistent custom tags schema
- User identification strategy
This structure makes Clarity data:
- Filterable: Find specific sessions easily
- Actionable: Understand user behavior patterns
- Maintainable: Update tracking without breaking analytics
Start simple: define 5-10 key events, implement the tracking wrapper, and iterate as you discover what data matters most.
Additional Resources:
- Event Tracking Setup – How to implement custom events
- Clarity JavaScript API Reference
- Google Tag Manager Integration