Microsoft Clarity Data Layer Setup | Blue Frog Docs

Microsoft Clarity Data Layer Setup

Structure and implement a data layer strategy for Microsoft Clarity custom events and user identification

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:

  1. Centralizes tracking logic – All tracking calls in one place, not scattered across your codebase
  2. Standardizes data format – Consistent naming, values, and structure
  3. Separates business logic from tracking – Developers can update features without breaking analytics
  4. 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

  1. Event Taxonomy – Standardized list of events you track
  2. Custom Tags Schema – Key-value pairs for session metadata
  3. User Identification Strategy – How you identify users
  4. 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_case for all event and tag names
  • Be consistent: checkout_started, checkout_complete (not Checkout 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: checkoutStarted vs. 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:

  1. Test in dev environment: Fire events, check console for errors
  2. Verify in Clarity dashboard: Confirm events appear in filters within 30 mins
  3. Watch recordings: Ensure events fire at the right moments
  4. Check data quality: Verify tag values are correct (not undefined or null)

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

  1. Create a GTM trigger: Custom Event = clarity_event
  2. Create a GTM tag: Custom HTML
  3. Tag template:
<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>
  1. 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 undefined when clarity("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:

  1. Centralized tracking wrapper (ClarityDataLayer)
  2. Standardized event taxonomy
  3. Consistent custom tags schema
  4. 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:

// SYS.FOOTER