Microsoft Clarity’s default tracking captures page views, clicks, and basic engagement signals. That’s enough for blog and content sites. For ecommerce, it’s nowhere near enough — you need to know which cart actions correlate with which session behaviors, which payment methods correlate with checkout abandonment, and which product categories drive rage-clicks on quantity selectors.

Custom tags are Clarity’s mechanism for attaching ecommerce-specific events to recorded sessions. Done well, they let you filter recordings by “sessions where user added 3+ items but abandoned at payment” or “sessions where user changed quantity 5+ times.” Those filtered views are where actionable CRO insights live.

This guide is the complete custom tag implementation framework for ecommerce in Microsoft Clarity. The tag taxonomy we deploy for Dallas ecommerce clients on Shopify, WooCommerce, and custom stacks. Code examples for every common cart action. Performance considerations for not tanking Core Web Vitals. And the 6 implementation mistakes that produce noisy or useless tag data.

TL;DR · Quick Summary

Microsoft Clarity custom tags add ecommerce-specific metadata to session recordings, enabling powerful filtering like “sessions where cart value > $200 but checkout abandoned” or “sessions that used PayPal vs credit card.” The right tag taxonomy covers: cart actions (add, remove, quantity change), funnel position (browse, cart, checkout step), commerce context (cart value, item count, category), and session outcome (purchase, abandonment with reason). Implementation via clarity("set", "tag", value) API. The framework below covers the full taxonomy, code patterns for Shopify/WooCommerce/custom stacks, INP-safe implementation, and how to act on the resulting filtered analyses.

Visual summary of Clarity Custom Tags Ecommerce Cart Clarity Tag Taxonomy 11 tags · 4 categories · unlimited filtering Funnel Position page_type · checkout_step Cart Actions cart_value · item_count Commerce Context customer_type · payment Outcome session_outcome · errors

What Custom Tags Actually Do in Clarity

Clarity custom tags are key-value pairs you attach to a session via JavaScript API calls. They’re searchable, filterable, and visible in the session details view. The API:

Clarity custom tag API
// Set a single tag
clarity("set", "cart_value", "247.50");

// Identify a user (use hashed identifier, not email)
clarity("identify", "user_hash_abc123");

// Set custom tag with array of values
clarity("set", "products_viewed", ["sku-001", "sku-042", "sku-099"]);

Once set, the tag appears in the session’s metadata and can be used to filter sessions in the dashboard. The filter syntax: “Show me sessions where cart_value > 200 AND session ended without purchase.”

This is dramatically more useful than the default Clarity setup because it lets you isolate high-value behavior patterns rather than wading through generic session lists.

Pro Tip — Tag Values Should Be Filterable, Not Descriptive

Use short, structured values for tags. clarity("set", "cart_step", "shipping") is filterable. clarity("set", "cart_note", "User reached shipping page after browsing 4 products") is unfilterable narrative text. Treat tags like database fields: short, structured, predictable values. Keep descriptive text in comments or other systems.

The Tag Taxonomy for Ecommerce

Clarity custom tag taxonomy — 4 categories Custom Tag Taxonomy Funnel Position page_type · home, product, cart, checkout checkout_step · contact, shipping, payment funnel_progress · browser, cart_adder Cart Actions cart_value_bucket · under_50, 500_to_1500 cart_item_count · 1, 2, 3, 5_plus cart_has_high_ticket · yes, no Commerce Context customer_type · guest, returning, vip payment_method · card, paypal, apple_pay discount_applied · yes, no Outcome session_outcome · purchase, abandoned abandonment_step · shipping, payment error_encountered · none, validation
Figure 2: The 4-quadrant tag taxonomy — funnel position, cart actions, commerce context, and session outcome. Most ecommerce filter needs fit within these four categories.

Across Dallas ecommerce implementations, this taxonomy covers 90%+ of useful filtering needs:

Funnel position tags

Tag nameValuesSet when
page_typehome, category, product, cart, checkout, successEvery page load
checkout_stepcontact, shipping, billing, payment, reviewEach checkout step
funnel_progressbrowser, cart_adder, checkout_starter, payment_reacherOn qualifying action

Cart action tags

Tag nameValuesSet when
cart_value_bucketunder_50, 50_to_200, 200_to_500, 500_to_1500, over_1500Cart updates
cart_item_count1, 2, 3, 4, 5_plusCart updates
cart_has_high_ticketyes, noWhen cart contains item over $500
cart_quantity_changes0, 1_to_3, 4_to_10, 10_plusTrack quantity edits

Commerce context tags

Tag nameValuesSet when
customer_typeguest, returning, vipOn checkout entry
payment_method_attemptedcard, paypal, apple_pay, google_pay, affirmPayment step
discount_appliedyes, noCart updates
shipping_methodstandard, express, white_glove, pickupShipping step
primary_categoryfurniture, electronics, apparel, etc.Cart updates

Outcome tags

Tag nameValuesSet when
session_outcomepurchase, abandoned_cart, abandoned_checkout, abandoned_payment, browsingSession end / exit intent
abandonment_stepcontact, shipping, billing, payment, reviewIf abandoned
error_encounterednone, validation, payment_declined, shipping, genericOn error event

Implementation on Shopify

For Shopify stores, the easiest pattern uses theme JavaScript with Liquid variable interpolation. Add to theme.liquid in the head:

Clarity setup for Shopify (theme.liquid)
<script>
(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");

// Set page_type based on Shopify template
{% if template == 'product' %}
  clarity("set", "page_type", "product");
{% elsif template == 'cart' %}
  clarity("set", "page_type", "cart");
{% elsif template contains 'checkout' %}
  clarity("set", "page_type", "checkout");
{% elsif template == 'index' %}
  clarity("set", "page_type", "home");
{% elsif template contains 'collection' %}
  clarity("set", "page_type", "category");
{% endif %}

// Customer type
{% if customer %}
  clarity("set", "customer_type", "returning");
  clarity("identify", "{{ customer.id | sha256 | slice: 0, 16 }}");
{% else %}
  clarity("set", "customer_type", "guest");
{% endif %}

// Cart-level data on cart and checkout pages
{% if cart.item_count > 0 %}
  <script>
  (function() {
    var value = {{ cart.total_price | divided_by: 100.0 }};
    var bucket = "under_50";
    if (value > 1500) bucket = "over_1500";
    else if (value > 500) bucket = "500_to_1500";
    else if (value > 200) bucket = "200_to_500";
    else if (value > 50) bucket = "50_to_200";
    clarity("set", "cart_value_bucket", bucket);
    
    var count = {{ cart.item_count }};
    var countBucket = count >= 5 ? "5_plus" : String(count);
    clarity("set", "cart_item_count", countBucket);
  })();
  </script>
{% endif %}
</script>

For dynamic cart updates (AJAX add-to-cart), hook into Shopify’s cart fetch API and re-set tags after every cart update.

Implementation on WooCommerce

For WooCommerce, use the wp_head hook in your theme’s functions.php:

Clarity setup for WooCommerce (functions.php)
function clarity_custom_tags() {
  if (!function_exists('WC')) return;
  
  $cart = WC()->cart;
  $total = $cart ? $cart->get_total('edit') : 0;
  $item_count = $cart ? $cart->get_cart_contents_count() : 0;
  
  $bucket = 'under_50';
  if ($total > 1500) $bucket = 'over_1500';
  else if ($total > 500) $bucket = '500_to_1500';
  else if ($total > 200) $bucket = '200_to_500';
  else if ($total > 50) $bucket = '50_to_200';
  
  $page_type = 'home';
  if (is_product()) $page_type = 'product';
  else if (is_cart()) $page_type = 'cart';
  else if (is_checkout()) $page_type = 'checkout';
  else if (is_shop() || is_product_category()) $page_type = 'category';
  
  $customer_type = is_user_logged_in() ? 'returning' : 'guest';
  
  ?>
  <script>
    clarity("set", "page_type", "<?php echo $page_type; ?>");
    clarity("set", "customer_type", "<?php echo $customer_type; ?>");
    <?php if ($item_count > 0): ?>
      clarity("set", "cart_value_bucket", "<?php echo $bucket; ?>");
      clarity("set", "cart_item_count", "<?php echo min($item_count, 5) === 5 ? '5_plus' : (string)$item_count; ?>");
    <?php endif; ?>
  </script>
  <?php
}
add_action('wp_head', 'clarity_custom_tags', 100);

For checkout step tracking, hook into WooCommerce’s checkout actions:

Checkout step tracking (WooCommerce)
// On checkout review page (Step 4)
add_action('woocommerce_review_order_before_payment', function() {
  echo '<script>clarity("set", "checkout_step", "payment");</script>';
});

// On thank-you page
add_action('woocommerce_thankyou', function($order_id) {
  $order = wc_get_order($order_id);
  $method = $order->get_payment_method();
  ?>
  <script>
    clarity("set", "session_outcome", "purchase");
    clarity("set", "payment_method_attempted", "<?php echo esc_js($method); ?>");
  </script>
  <?php
});

Implementation on Custom Stacks (React, Vue, etc.)

For custom-built ecommerce (Next.js, Vue, React), wrap Clarity calls in a utility module:

Custom React/Next.js Clarity wrapper
// utils/clarity.js
export function clarity(...args) {
  if (typeof window !== 'undefined' && window.clarity) {
    window.clarity(...args);
  }
}

export function tagPageType(type) {
  clarity("set", "page_type", type);
}

export function tagCartUpdate(cart) {
  const total = cart.total;
  let bucket = "under_50";
  if (total > 1500) bucket = "over_1500";
  else if (total > 500) bucket = "500_to_1500";
  else if (total > 200) bucket = "200_to_500";
  else if (total > 50) bucket = "50_to_200";
  
  clarity("set", "cart_value_bucket", bucket);
  clarity("set", "cart_item_count", cart.itemCount >= 5 ? "5_plus" : String(cart.itemCount));
}

export function tagCheckoutStep(step) {
  clarity("set", "checkout_step", step);
}

export function tagSessionOutcome(outcome) {
  clarity("set", "session_outcome", outcome);
}

// In your cart store/reducer:
import { tagCartUpdate } from '../utils/clarity';
function cartReducer(state, action) {
  const newState = /* reducer logic */;
  tagCartUpdate(newState);
  return newState;
}
Don’t Send PII in Custom Tags

Tag values are searchable in the Clarity dashboard and stored long-term. Never include email addresses, phone numbers, names, or credit card data as tag values. For user identification, use clarity("identify", hashedId) with a SHA-256 hash of the user ID, not the raw email. PII in tags violates Clarity’s terms of service and GDPR; both will get you flagged and potentially delisted.

Performance Impact: Keeping INP Under 200ms

Each clarity("set", ...) call adds a tiny amount of work to the main thread. Individual calls are negligible. Batching them on every cart update can add up. Optimization patterns:

  • Debounce cart-update tags. If a user rapidly changes quantity 5 times, set tags only after the last change (300ms debounce). Don’t set 5 cart_value_bucket tags in quick succession.
  • Use requestIdleCallback for non-critical tags. Wrap analytics calls in requestIdleCallback(() => clarity("set", "primary_category", category)) so they run during browser idle time.
  • Limit total tags per session. Clarity allows up to 50 tags. Aim for 10–15 for clean filtering. More than that adds dashboard noise.
  • Don’t set tags in render-blocking paths. Page-type tags should be set after first paint, not inline in the <head> for synchronous-render content. Use the API after DOMContentLoaded.
  • Cache tag values client-side. If cart_value_bucket hasn’t changed, don’t re-set it. Compare against previous value before calling the API.

Filtering and Acting on Tag Data

Once tags are flowing, the real value comes from the filtered analyses you can run. Examples of high-impact filter queries:

  • “Show me sessions where cart_value > 500 AND session_outcome = abandoned_payment” — high-ticket payment abandonment, the highest-value cohort to study
  • “Show me sessions where payment_method_attempted = paypal AND session_outcome = abandoned” — reveals if PayPal flow has bugs
  • “Show me sessions where checkout_step = shipping AND device = mobile” — shipping form mobile friction
  • “Show me sessions where cart_quantity_changes > 4” — users struggling with quantity selector UX
  • “Show me sessions where customer_type = vip AND session_outcome = abandoned_cart” — high-value customers leaving without purchasing (urgent)

Each filtered view gives you 20–100 specific sessions to watch using the 5-step framework from our rage-click diagnosis guide. The combination of structured tagging + filtered analysis is where the conversion lift opportunities live.

Real Case: Dallas Apparel Brand Recovers 24% of High-Ticket Abandonment

In December 2025 we implemented this taxonomy for a Dallas-based women’s apparel brand (DTC, $6.4M ARR). Their pre-implementation state: Clarity installed, default config, no custom tags. They knew abandonment was a problem but couldn’t isolate which cohort or step.

Implementation:

  • Added 11 custom tags following the taxonomy above
  • Wired up Shopify theme.liquid + AJAX cart updates
  • Server-side conversion tracking via Meta Conversions API for redundancy — see our Meta CAPI setup guide

First analysis (3 weeks of data):

  • Filter “cart_value_bucket = 200_to_500 AND session_outcome = abandoned_payment” surfaced 87 sessions
  • Watching 30 of these revealed: 19/30 abandoned on the credit card field (autofill broken)
  • Filter “payment_method_attempted = apple_pay” surfaced 240 sessions, 89% completed (vs 58% completion for card)

Actions taken:

  • Fixed autofill on credit card field (removed conflicting autocomplete="off")
  • Made Apple Pay the primary mobile payment option (was below the fold previously)
  • Added Google Pay alongside Apple Pay (was missing entirely)
Result, 8 weeks later “Payment-step abandonment dropped from 38% to 22%. Mobile checkout completion rose 41%. Without the custom tag taxonomy, we would have known abandonment was a problem; we wouldn’t have known WHICH cart segment, WHICH device, or WHICH payment method was the leak. The targeted fixes would have taken weeks of guesswork to identify otherwise.”

The 6 Mistakes That Make Custom Tags Useless

  • 1. Free-text values instead of buckets. Setting cart_value to "247.50" is unfilterable in practice (every session has a unique value). Use buckets like "200_to_500".
  • 2. Not setting tags after dynamic updates. Single-page app cart changes don’t trigger page loads. Hook into cart update events explicitly.
  • 3. Setting page_type but not cart context. Knowing the page isn’t enough. The cart state, customer type, and funnel position are what enable useful filtering.
  • 4. Tag spam. Setting 30+ tags per session creates dashboard noise without adding insight value. Stick to 10–15 well-chosen tags.
  • 5. Inconsistent tag naming. Mix of cart_value, cartValue, cart-value across pages makes filtering unreliable. Pick one naming convention (snake_case recommended) and enforce it.
  • 6. Not setting outcome tags. Without session_outcome set on every session, you can’t filter abandoners vs purchasers. This is the most valuable single tag and most often forgotten. Set it on the success page AND on exit-intent or session-end events.

Advanced Patterns Worth Considering

Once the base taxonomy is working, several advanced patterns unlock additional analysis:

  • A/B test variant tagging. If you’re running tests, set ab_test_variant to track which variant the user saw. Cross-reference with session outcomes to understand which variant produces which behaviors.
  • Discount code tagging. Set discount_code to which code was applied (not the value). Reveals which promotions drive completion vs cart-shopping behavior.
  • Time-of-day tagging. Set visit_hour_bucket (morning, afternoon, evening, late_night). Reveals time-based patterns — some businesses see dramatically different conversion rates by time of day.
  • Source-medium tagging. Set traffic_source beyond what Clarity captures by default (e.g., paid_google, organic_search, email_nurture_week3). Filter rage-clicks by source — paid traffic users have different expectations than organic.
  • Error event tagging. Set error_encountered with the specific error type. Filter to sessions where errors occurred to diagnose recurring issues. Pair with the framework in JavaScript errors vs user frustration.

For Dallas ecommerce clients with $1M+ annual revenue, the custom tag taxonomy is one of the highest-ROI analytics investments available. Implementation takes 6–15 dev hours; the insights generated drive multi-quarter optimization roadmaps. The full implementation pairs with the broader audit framework in Clarity vs Hotjar in 2026 — tag-driven filtering is what makes either tool actually useful for serious CRO.

Frequently Asked Questions

How many custom tags can I set per session in Clarity?

Clarity allows up to 50 tags per session. In practice, aim for 10–15 well-chosen tags. More than 20 makes the dashboard noisy and degrades performance. Quality over quantity: a few well-structured tags with bucketed values unlock more filtering power than 30 random free-text tags.

Do I need to upgrade to Clarity Plus or another paid tier for custom tags?

No. Custom tags are available on the free tier of Microsoft Clarity, with no quota limits. Clarity remains free for unlimited traffic and unlimited sessions (Microsoft monetizes through Bing data, not subscriptions). If you’re comparing to Hotjar, this is a key reason teams switch to Clarity for ecommerce analytics specifically.

Can I retroactively add tags to existing sessions?

No — tags must be set during the live session. If you implement tags today, you start collecting filterable data going forward. Plan implementation to run for 3–6 weeks before drawing conclusions, especially for less-frequent behaviors (high-ticket abandonment). For analysis you need on historical data, you’ll need to rely on the default session metadata Clarity already captures (page, device, source).

How do custom tags interact with Consent Mode v2?

Clarity respects user consent state. If the user denies tracking consent, Clarity doesn’t record or tag the session. If consent is granted, tags work normally. If consent state changes mid-session (rare but possible), behavior depends on your Consent Management Platform’s integration. For Dallas clients targeting EU traffic, we recommend explicit consent banners that activate Clarity only after consent — not the default opt-out approach.

Will custom tags hurt my page speed?

Negligibly, if implemented correctly. Each clarity("set", ...) call adds <1ms to the main thread. The risk is in batched cart updates where you might fire 10 tags in 50ms during a rapid cart change. Use the debounce/idle-callback patterns above to avoid this. Total Interaction to Next Paint (INP) impact of a well-implemented tag system: under 5ms even on cart-heavy sessions.

Need help implementing Clarity custom tags?

We’ll deploy the full ecommerce tag taxonomy for your Shopify, WooCommerce, or custom stack — including INP-safe implementation, consent compliance, and dashboard setup for filtered analyses. Typical turnaround: 1–2 weeks.

Get a Clarity Setup Audit Explore Ecommerce SEO Services