How to Fix Kentico Tracking Events Not Firing | OpsBlu Docs

How to Fix Kentico Tracking Events Not Firing

Fix GA4, GTM, and pixel events not firing on Kentico Xperience — master page script injection, web part conflicts, and output cache debugging

This guide helps you diagnose and fix common issues when analytics events aren't firing on Kentico Xperience websites.

Quick Diagnostic Checklist

Before diving deep, run through this quick checklist:

  • Tracking code visible in page source
  • Correct tracking ID/pixel ID/container ID
  • No JavaScript errors in console
  • Not blocked by ad blocker
  • Correct environment (not staging)
  • User has given consent (if using consent management)
  • Browser cache cleared
  • Testing in incognito/private mode

Browser Console Diagnostics

Check for JavaScript Errors

  1. Open DevTools (F12)
  2. Go to Console tab
  3. Look for red errors
  4. Common errors:
    • gtag is not defined
    • fbq is not defined
    • dataLayer is not defined

Verify Tracking Functions Loaded

// In browser console, type:

// Check if GA4 is loaded
typeof gtag
// Should return "function"

// Check if Meta Pixel is loaded
typeof fbq
// Should return "function"

// Check if GTM dataLayer exists
typeof dataLayer
// Should return "object"

// Check GTM container
typeof google_tag_manager
// Should return "object"

Test Events Manually

// Test GA4 event
gtag('event', 'test_event', { test_param: 'test_value' });

// Test Meta Pixel event
fbq('track', 'PageView');
fbq('trackCustom', 'TestEvent', { test: 'value' });

// Test GTM dataLayer
dataLayer.push({ 'event': 'test_event', 'test_param': 'test_value' });

Google Analytics 4 Troubleshooting

Issue: GA4 Not Loading

Check if gtag.js is Present

View page source (Ctrl+U) and search for:

https://www.googletagmanager.com/gtag/js?id=G-

If not found:

Solution 1: Verify Layout File

@using CMS.Helpers
@{
    var gaId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", SiteContext.CurrentSiteID);
}

@if (!string.IsNullOrEmpty(gaId))
{
    <script async src="https://www.googletagmanager.com/gtag/js?id=@gaId"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', '@gaId');
    </script>
}
else
{
    <!-- DEBUG: GA4 ID is empty -->
}

Solution 2: Check Kentico Settings

  1. Go to SettingsIntegrationGoogle
  2. Verify GoogleAnalyticsMeasurementID exists
  3. Check value format: G-XXXXXXXXXX (not UA- or GTM-)
  4. Ensure setting is at correct site level (multi-site)

Check for Environment Blocking

@{
    var isProduction = SiteContext.CurrentSite.SiteName == "ProductionSite";
    var gaId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", SiteContext.CurrentSiteID);

    // DEBUG: Add this temporarily
    var debugInfo = $"Site: {SiteContext.CurrentSite.SiteName}, IsProduction: {isProduction}, GA ID: {gaId}";
}

<!-- Debug info (remove in production): @debugInfo -->

@if (isProduction && !string.IsNullOrEmpty(gaId))
{
    <!-- GA4 code -->
}

Issue: GA4 Events Not Firing

Enable Debug Mode

<script>
  gtag('config', 'G-XXXXXXXXXX', {
    'debug_mode': true
  });
</script>

Then check GA4 → Configure → DebugView

Verify Event Syntax

// INCORRECT
gtag('event', 'purchase' {
  value: 100  // Missing comma before object
});

// CORRECT
gtag('event', 'purchase', {
  value: 100,
  currency: 'USD'
});

Check Event Timing

// BAD: Event fires before gtag is loaded
gtag('event', 'page_view');

// GOOD: Wait for gtag to load
window.addEventListener('load', function() {
  gtag('event', 'page_view');
});

Verify in Network Tab

  1. Open DevTools → Network tab
  2. Filter by "collect"
  3. Trigger your event
  4. Look for requests to google-analytics.com/g/collect
  5. Click request → Payload tab
  6. Verify event name and parameters

Issue: E-commerce Events Not Tracking

Check Purchase Event Implementation

@using CMS.Ecommerce
@model OrderInfo

@{
    var purchaseTracked = SessionHelper.GetValue("GA4_Purchase_" + Model.OrderID);
}

<!-- Debug: Purchase Tracked = @purchaseTracked -->

@if (purchaseTracked == null)
{
    SessionHelper.SetValue("GA4_Purchase_" + Model.OrderID, true);

    <script>
      console.log('Tracking purchase:', {
        transaction_id: '@Model.OrderID',
        value: @Model.OrderGrandTotal,
        currency: '@Model.OrderCurrency.CurrencyCode'
      });

      gtag('event', 'purchase', {
        transaction_id: '@Model.OrderID',
        value: @Model.OrderGrandTotal,
        currency: '@Model.OrderCurrency.CurrencyCode',
        items: [
          @foreach (var item in Model.OrderItems)
          {
            @:{
              item_id: '@item.OrderItemSKU.SKUNumber',
              item_name: '@item.OrderItemSKU.SKUName',
              price: @item.OrderItemUnitPrice,
              quantity: @item.OrderItemUnitCount
            }@(item != Model.OrderItems.Last() ? "," : "")
          }
        ]
      });
    </script>
}

Common E-commerce Issues

Problem: Currency not a 3-letter code

// BAD
currency: 'Dollar'

// GOOD
currency: 'USD'

Problem: Value is string instead of number

// BAD
value: '@Model.OrderGrandTotal'  // String with quotes

// GOOD
value: @Model.OrderGrandTotal     // Number without quotes

Google Tag Manager Troubleshooting

Issue: GTM Not Loading

Verify Container Code

View page source and search for: googletagmanager.com/gtm.js?id=GTM-

If not found, check layout file:

<!DOCTYPE html>
<html>
<head>
    <!-- THIS MUST BE IN HEAD -->
    @{
        var gtmId = SettingsKeyInfoProvider.GetValue("GoogleTagManagerID", SiteContext.CurrentSiteID);
    }

    @if (!string.IsNullOrEmpty(gtmId))
    {
        <!-- Google Tag Manager -->
        <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
        new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
        j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
        'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
        })(window,document,'script','dataLayer','@gtmId');</script>
        <!-- End Google Tag Manager -->
    }
    else
    {
        <!-- DEBUG: GTM ID is empty! -->
    }
</head>
<body>
    <!-- THIS MUST BE AT START OF BODY -->
    @if (!string.IsNullOrEmpty(gtmId))
    {
        <!-- Google Tag Manager (noscript) -->
        <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=@gtmId"
        height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
        <!-- End Google Tag Manager (noscript) -->
    }

    @RenderBody()
</body>
</html>

Check Container Published

  1. Open GTM
  2. Verify container has been published (not just saved)
  3. Check Versions tab for latest version
  4. Publish if needed

Issue: GTM Tags Not Firing

Use Preview Mode

  1. Open GTM
  2. Click Preview
  3. Enter your Kentico site URL
  4. GTM debugger opens

In debugger:

  • Summary tab shows tags fired/not fired
  • Variables tab shows variable values
  • Data Layer tab shows data layer events
  • Errors tab shows problems

Check Triggers

Common trigger issues:

Issue: Trigger condition not met

// Trigger: Click - All Elements
// Condition: Click URL contains "download"

// This WON'T fire because link uses JavaScript onclick
<a href="#"

// This WILL fire
<a href="/downloads/file.pdf">Download</a>

Solution: Adjust trigger conditions or add data attributes

<a href="#"
   data-download="true">Download</a>
// Trigger: Click - All Elements
// Condition: Click Element matches CSS selector a[data-download]

Check Variables

Issue: Variable returns undefined

// In GTM, check variable configuration
// Variable Type: Data Layer Variable
// Data Layer Variable Name: ecommerce.value

// In your page, verify structure:
dataLayer.push({
  'ecommerce': {
    'value': 100  // Variable will find this
  }
});

Debug variables in console:

// List all dataLayer events
console.table(dataLayer);

// Check specific variable
dataLayer.filter(item => item.event === 'purchase');

Issue: Data Layer Not Populating

Check Initialization

<!-- Data Layer MUST be defined BEFORE GTM container -->

<!-- CORRECT ORDER -->
<script>
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    'pageType': 'product',
    'productId': '12345'
  });
</script>

<!-- GTM Container code here -->

<!-- WRONG: GTM loads first -->
<!-- GTM Container -->
<script>
  window.dataLayer.push({ ... });  // Too late!
</script>

Verify Kentico Data Layer Structure

@using CMS.DocumentEngine
@using Newtonsoft.Json

@{
    var currentDoc = DocumentContext.CurrentDocument;
    var pageData = new {
        pageType = currentDoc.ClassName,
        pageName = currentDoc.DocumentName,
        pageId = currentDoc.DocumentID
    };
}

<script>
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push(@Html.Raw(JsonConvert.SerializeObject(new {
      pageData = pageData
  })));

  // Debug: Log to console
  console.log('Data Layer:', window.dataLayer);
</script>

Meta Pixel Troubleshooting

Issue: Pixel Not Loading

Check Pixel Code Present

View source and search for: connect.facebook.net/en_US/fbevents.js

If not found:

@{
    var pixelId = SettingsKeyInfoProvider.GetValue("FacebookPixelID", SiteContext.CurrentSiteID);
}

<!-- Debug: Pixel ID = @pixelId -->

@if (!string.IsNullOrEmpty(pixelId))
{
    <script>
      !function(f,b,e,v,n,t,s)
      {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
      n.callMethod.apply(n,arguments):n.queue.push(arguments)};
      if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
      n.queue=[];t=b.createElement(e);t.async=!0;
      t.src=v;s=b.getElementsByTagName(e)[0];
      s.parentNode.insertBefore(t,s)}(window, document,'script',
      'https://connect.facebook.net/en_US/fbevents.js');

      console.log('Initializing Meta Pixel:', '@pixelId');
      fbq('init', '@pixelId');
      fbq('track', 'PageView');
    </script>
}

Use Meta Pixel Helper

  1. Install Meta Pixel Helper Chrome extension
  2. Navigate to your site
  3. Click extension icon
  4. Check for:
    • ✓ Pixel found
    • Pixel ID matches yours
    • Events firing
    • No errors

Issue: Pixel Events Not Firing

Check Event Order

// BAD: Event fires before pixel loaded
fbq('track', 'AddToCart');  // Error: fbq not defined

// GOOD: Ensure pixel loads first
if (typeof fbq !== 'undefined') {
  fbq('track', 'AddToCart', {
    content_ids: ['12345'],
    content_type: 'product'
  });
}

Verify Event Parameters

// Check in browser console
window._fbq.instance.pendingConfigs
// Shows all pixel configurations

// Check events queue
window._fbq.instance.queue
// Shows queued events

Common Event Issues

Issue: Event name incorrect (case-sensitive)

// WRONG
fbq('track', 'addToCart');  // Lowercase

// CORRECT
fbq('track', 'AddToCart');  // Proper case

Issue: Missing content_ids for e-commerce events

// INCOMPLETE
fbq('track', 'Purchase', {
  value: 100,
  currency: 'USD'
  // Missing content_ids!
});

// COMPLETE
fbq('track', 'Purchase', {
  value: 100,
  currency: 'USD',
  content_ids: ['SKU123', 'SKU456']
});

Issue: Events in Test Events But Not Production

Check Pixel Deduplication

If using both browser pixel and Conversions API:

fbq('track', 'Purchase', {
  value: 100,
  currency: 'USD'
}, {
  eventID: 'purchase_@Model.OrderID'  // Unique event ID
});

Server-side must use same eventID.

Kentico-Specific Issues

Issue: Tracking Works on Some Page Types, Not Others

Check Page Template

Different templates may have different layouts:

@{
    // Add debug to identify which layout is loading
    var layoutUsed = "Main Layout";
}
<!-- DEBUG: Layout = @layoutUsed -->

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

Check Portal Engine Master Pages

In Portal Engine, different page types might use different master pages:

  1. Go to DesignPage templates
  2. Check each template's master page
  3. Ensure all have tracking code

Solution: Centralize Tracking Code

Create a shared partial view:

<!-- Views/Shared/_Tracking.cshtml -->
@using CMS.Helpers

@{
    var gtmId = SettingsKeyInfoProvider.GetValue("GoogleTagManagerID", SiteContext.CurrentSiteID);
    var gaId = SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", SiteContext.CurrentSiteID);
}

@if (!string.IsNullOrEmpty(gtmId))
{
    <!-- GTM code -->
}

@if (!string.IsNullOrEmpty(gaId))
{
    <!-- GA4 code -->
}

Then include in all layouts:

@Html.Partial("_Tracking")

Issue: Events Fire in Development, Not Production

Check Environment Conditionals

@{
    var siteName = SiteContext.CurrentSite.SiteName;
    var isProduction = siteName == "ProductionSite";  // Check this matches!
}

<!-- Debug: Site Name = @siteName, Is Production = @isProduction -->

@if (isProduction)
{
    <!-- Tracking code -->
}

Check Setting Inheritance

Settings might be defined at global level but overridden at site level:

  1. Go to Settings[Your Site Name]
  2. Check if setting exists at site level
  3. Verify value is correct for that site

Issue: ViewState Interfering (Portal Engine)

Large ViewState can cause timing issues:

<!-- web.config -->
<appSettings>
  <!-- Disable ViewState if not needed -->
  <add key="CMSControlState" value="false" />
</appSettings>

<!-- Or per-page -->
<%@ Page EnableViewState="false" %>
// In console, check consent status
// For OneTrust
console.log(OptanonActiveGroups);

// For Cookiebot
console.log(Cookiebot.consent);

// For custom implementation
console.log(localStorage.getItem('analyticsConsent'));
<script>
  function loadTracking() {
    if (hasUserConsent()) {
      // Load GTM
      (function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXXXXX');
    }
  }

  function hasUserConsent() {
    // Your consent check logic
    return localStorage.getItem('analyticsConsent') === 'true';
  }

  // Load on consent granted
  window.addEventListener('consentGranted', loadTracking);

  // Check on page load
  if (hasUserConsent()) {
    loadTracking();
  }
</script>

Network-Level Issues

Issue: Content Security Policy (CSP) Blocking

Check browser console for CSP errors:

Refused to load the script 'https://www.googletagmanager.com/gtm.js'
because it violates the following Content Security Policy directive

Solution: Update CSP headers

<!-- web.config -->
<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Content-Security-Policy"
           value="script-src 'self' 'unsafe-inline' https://www.googletagmanager.com https://www.google-analytics.com https://connect.facebook.net;" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Issue: Ad Blockers

Ad blockers can prevent tracking:

For testing:

  1. Disable ad blocker
  2. Use incognito mode
  3. Test on mobile device

For detection:

<script>
  // Detect ad blocker
  var testAd = document.createElement('div');
  testAd.innerHTML = '&nbsp;';
  testAd.className = 'adsbox';
  document.body.appendChild(testAd);

  window.setTimeout(function() {
    if (testAd.offsetHeight === 0) {
      console.warn('Ad blocker detected - tracking may be blocked');
    }
    testAd.remove();
  }, 100);
</script>

Debugging Tools

Enable All Debugging

<script>
  // Log all GTM events
  window.dataLayer = window.dataLayer || [];
  var originalPush = window.dataLayer.push;
  window.dataLayer.push = function() {
    console.log('GTM Event:', arguments);
    return originalPush.apply(window.dataLayer, arguments);
  };

  // Log all GA4 events
  window.gtag = window.gtag || function() {
    console.log('GA4 Event:', arguments);
    window.dataLayer.push(arguments);
  };

  // Log all Meta Pixel events
  window.fbq = window.fbq || function() {
    console.log('Meta Pixel Event:', arguments);
  };
</script>

Create Debug Panel

@if (User.IsInRole("Administrator"))
{
    <div id="debug-panel" style="position: fixed; bottom: 0; right: 0; background: #000; color: #0f0; padding: 10px; font-family: monospace; font-size: 12px; max-height: 300px; overflow-y: auto; z-index: 9999;">
        <h4>Debug Info</h4>
        <p>Site: @SiteContext.CurrentSite.SiteName</p>
        <p>GTM ID: @SettingsKeyInfoProvider.GetValue("GoogleTagManagerID", SiteContext.CurrentSiteID)</p>
        <p>GA4 ID: @SettingsKeyInfoProvider.GetValue("GoogleAnalyticsMeasurementID", SiteContext.CurrentSiteID)</p>
        <p>Pixel ID: @SettingsKeyInfoProvider.GetValue("FacebookPixelID", SiteContext.CurrentSiteID)</p>
        <p>Page Type: @DocumentContext.CurrentDocument?.ClassName</p>
        <button window.dataLayer)">Log DataLayer</button>
        <button google_tag_manager)">Log GTM</button>
    </div>
}

Testing Checklist

Before declaring victory, test:

  • Page view tracking works
  • Custom events fire correctly
  • E-commerce events track properly
  • Events appear in analytics platform
  • Works across all page templates
  • Works on mobile devices
  • Works in all major browsers
  • Consent management doesn't break tracking
  • No duplicate events
  • Production environment tracking correctly

Getting Help

If you're still stuck:

  1. Check Kentico Event Log: System → Event log
  2. Review Browser Console: Any JavaScript errors?
  3. Use Debugging Tools: GTM Preview, GA4 DebugView, Meta Pixel Helper
  4. Test in Isolation: Create a simple test page
  5. Compare Working vs Non-Working: What's different?
  6. Ask Community: Kentico DevNet, analytics forums

Additional Resources