How to Fix Episerver (Optimizely) Events Not Firing | OpsBlu Docs

How to Fix Episerver (Optimizely) Events Not Firing

Fix GA4, GTM, and pixel events not firing on Episerver — SPA route change tracking, Content Delivery API event timing, and Commerce checkout debugging

Complete guide to diagnosing and fixing analytics event tracking issues on Episerver (Optimizely) CMS and Commerce.

Quick Diagnosis

Symptoms Checklist

Check which symptoms apply to your situation:

  • No events firing at all
  • Events fire in development but not production
  • Events fire sometimes but not consistently
  • Events fire multiple times (duplicates)
  • Events fire in view mode but not after publishing
  • Events fire on some browsers but not others
  • Events show in browser console but not in analytics

Step-by-Step Diagnosis

Step 1: Verify Base Tracking Installation

Check GA4 Installation

// Open browser console and run:
console.log(typeof gtag);
// Should output: "function"

// Check if GA4 is loaded
console.log(window.dataLayer);
// Should show array with gtag config

If gtag is undefined:

  • GA4 script not loaded
  • Script blocked by ad blocker
  • Script blocked by Content Security Policy
  • Edit mode check preventing load

Check GTM Installation

// Open browser console and run:
console.log(typeof google_tag_manager);
// Should output: "object"

console.log(window.dataLayer);
// Should show array with GTM data

Check Meta Pixel Installation

// Open browser console and run:
console.log(typeof fbq);
// Should output: "function"

// Check pixel queue
console.log(window._fbq);

Step 2: Check Edit Mode

Most common cause: Events disabled in Episerver edit mode

Verify Edit Mode Check

@{
    var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
    // For CMS 11: PageEditing.PageIsInEditMode(HttpContext)
}

<!-- Add temporary diagnostic -->
<div style="position: fixed; top: 0; right: 0; background: red; color: white; padding: 10px; z-index: 9999;">
    Edit Mode: @isEditMode
</div>

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

Common Issues:

  1. Wrong Method (CMS 11 vs 12)
// CMS 12+ (Correct)
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;

// CMS 11 (Correct)
var isEditMode = PageEditing.PageIsInEditMode(HttpContext);

// Wrong - Always false
var isEditMode = false; // Hard-coded!
  1. Preview Mode Confusion
var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
var isPreviewMode = EPiServer.Web.ContextMode.Current == EPiServer.Web.ContextMode.Preview;

// Should tracking fire in preview?
if (!isEditMode && !isPreviewMode)
{
    // Won't track in preview mode
}

Step 3: Check Browser Console for Errors

Open DevTools (F12) → Console tab

Common JavaScript Errors

Error: "gtag is not defined"

Uncaught ReferenceError: gtag is not defined

Causes:

  • GA4 script not loaded
  • Event fires before gtag loads
  • Script blocked

Solution:

// Wrap events in check
if (typeof gtag === 'function') {
  gtag('event', 'event_name', { /* params */ });
} else {
  console.warn('gtag not loaded');
}

// Or wait for load
window.addEventListener('load', function() {
  if (typeof gtag === 'function') {
    gtag('event', 'event_name', { /* params */ });
  }
});

Error: "fbq is not defined"

Solution:

// Check before calling
if (typeof fbq === 'function') {
  fbq('track', 'EventName', { /* params */ });
}

Error: "Syntax error"

Uncaught SyntaxError: Unexpected token

Cause: Invalid JSON or JavaScript syntax

Check:

<!-- BAD: Missing quotes -->
<script>
  gtag('event', 'click', {
    value: @Model.Price  // Missing quotes around string
  });
</script>

<!-- GOOD: Proper syntax -->
<script>
  gtag('event', 'click', {
    value: @Model.Price,
    item_name: '@Model.Name'  // Quoted string
  });
</script>

Step 4: Check Network Tab

Open DevTools (F12) → Network tab

For GA4

Filter: google-analytics.com or collect

Look for:

  • gtag/js?id=G-XXXXXXXXXX (GA4 script load)
  • Requests to /g/collect? (event tracking)

Status codes:

  • 200 - Success
  • 0 or (failed) - Blocked
  • 404 - Incorrect URL

If no requests:

  • Events not firing
  • Ad blocker enabled
  • CSP blocking requests

For GTM

Filter: googletagmanager.com

Look for:

  • gtm.js?id=GTM-XXXXXXX (GTM script)
  • Should see 200 status

For Meta Pixel

Filter: facebook.com

Look for:

  • fbevents.js (Pixel script)
  • tr? requests (event tracking)

Step 5: Check GTM Debug Mode

If using GTM:

  1. Click Preview in GTM container
  2. Enter your Episerver site URL
  3. GTM debugger window opens
  4. Perform action (e.g., click button)
  5. Check if event appears in debugger

Not appearing?

  • Data layer push not working
  • Event name mismatch
  • Trigger not configured

Debug data layer:

// Console
console.log(window.dataLayer);

// Watch for pushes
var originalPush = window.dataLayer.push;
window.dataLayer.push = function() {
  console.log('Data Layer Push:', arguments);
  return originalPush.apply(this, arguments);
};

Step 6: Check Tag Assistants

Google Tag Assistant

  1. Install Google Tag Assistant
  2. Click "Connect" and enter URL
  3. Navigate and interact with site
  4. Review detected tags and events

Meta Pixel Helper

  1. Install Meta Pixel Helper
  2. Visit your site
  3. Click extension icon
  4. Verify pixel status and events

Common Episerver-Specific Issues

Issue 1: Events Fire in Edit Mode

Problem: Analytics tracking editors instead of visitors

Diagnosis:

<!-- Check if edit mode protection exists -->
@if (!isEditMode)
{
    <script>
      gtag('event', 'page_view');
    </script>
}

Solution:

@{
    var isEditMode = EPiServer.Editor.PageEditing.PageIsInEditMode;
}

@if (!isEditMode)
{
    <!-- ALL tracking code here -->
}

Issue 2: Events Don't Fire After Publishing

Problem: Works in preview but not on live site

Causes:

  1. Different tracking IDs for staging/production
  2. Caching issues
  3. Preview mode check too restrictive

Solution:

Check environment-specific configuration:

// appsettings.Production.json
{
  "GoogleAnalytics": {
    "MeasurementId": "G-PRODUCTION"
  }
}

// appsettings.Staging.json
{
  "GoogleAnalytics": {
    "MeasurementId": "G-STAGING"
  }
}

Clear cache:

# Clear Episerver cache
# In Episerver admin: Admin → Config → Cache → Clear All

Issue 3: Commerce Events Missing Data

Problem: Ecommerce events fire but missing product data

Check data layer structure:

// Console
window.dataLayer.forEach((item, i) => {
  if (item.ecommerce) {
    console.log('Item ' + i + ':', item.ecommerce);
  }
});

Common Issues:

// BAD: Null reference
var price = variant.GetDefaultPrice().UnitPrice.Amount;
// Throws error if no default price

// GOOD: Null check
var price = variant.GetDefaultPrice()?.UnitPrice.Amount ?? 0;
<!-- BAD: Invalid JSON -->
<script>
  gtag('event', 'purchase', {
    items: @Model.Items  // Wrong - outputs object, not JSON
  });
</script>

<!-- GOOD: Proper JSON serialization -->
<script>
  gtag('event', 'purchase', {
    items: @Html.Raw(JsonConvert.SerializeObject(Model.Items))
  });
</script>

Issue 4: Multi-Site Wrong Tracking ID

Problem: Site A tracking to Site B's property

Diagnosis:

// Add debug output
var currentSite = SiteDefinition.Current;
var trackingId = currentSite.GetGATrackingId();

_logger.Information($"Site: {currentSite.Name}, Tracking ID: {trackingId}");

Solution:

public static string GetGATrackingId(this SiteDefinition site)
{
    // Use host-based routing
    return site.SiteUrl.Host switch
    {
        "www.site1.com" => "G-SITE1XXXX",
        "www.site2.com" => "G-SITE2XXXX",
        _ => null
    };
}

Issue 5: Event Fires Multiple Times

Problem: Same event tracked 2-3 times

Causes:

  1. Multiple tracking implementations
  2. Event bound multiple times
  3. Page includes script multiple times

Diagnosis:

# Search for duplicate implementations
grep -r "gtag('event'" .
grep -r "fbq('track'" .

# Check for multiple GTM containers
grep -r "GTM-" .

Solution:

Remove duplicates and implement once:

// Prevent duplicate event binding
var eventsInitialized = false;

function initializeEvents() {
  if (eventsInitialized) return;
  eventsInitialized = true;

  document.querySelector('#my-button').addEventListener('click', function() {
    gtag('event', 'button_click');
  });
}

// Call once
initializeEvents();

Content Security Policy (CSP) Issues

Diagnosis

Error in Console:

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

Solution

Update CSP headers in web.config:

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

For CMS 12+, use middleware:

public void Configure(IApplicationBuilder app)
{
    app.Use(async (context, next) =>
    {
        context.Response.Headers.Add("Content-Security-Policy",
            "script-src 'self' 'unsafe-inline' https://*.googletagmanager.com https://*.google-analytics.com");
        await next();
    });
}

Ad Blocker Issues

Diagnosis

Symptoms:

  • Works with ad blocker disabled
  • No requests in Network tab when enabled
  • Tag assistants don't detect tags

Note: This is expected behavior. Ad blockers intentionally block analytics.

Solutions

  1. Test with ad blockers disabled

    • Disable temporarily for testing
    • Use incognito/private mode
    • Test on different browser
  2. Inform stakeholders

    • 20-30% of users use ad blockers
    • This is expected and acceptable
    • Focus on users without blockers
  3. Server-side tracking (optional)

Debugging Tools and Scripts

Event Listener Logger

// Log all GTM data layer pushes
(function() {
  var originalPush = Array.prototype.push;
  window.dataLayer = window.dataLayer || [];

  window.dataLayer.push = function() {
    console.log('DataLayer Push:', arguments);
    return originalPush.apply(this, arguments);
  };
})();

GA4 Event Logger

// Override gtag to log all calls
(function() {
  if (typeof gtag !== 'function') return;

  var originalGtag = gtag;
  window.gtag = function() {
    console.log('gtag called:', arguments);
    return originalGtag.apply(this, arguments);
  };
})();

Meta Pixel Event Logger

// Log all Meta Pixel events
(function() {
  if (typeof fbq !== 'function') return;

  var originalFbq = fbq;
  window.fbq = function() {
    console.log('fbq called:', arguments);
    return originalFbq.apply(this, arguments);
  };
})();

Comprehensive Tracking Diagnostic

// Run this in console for complete diagnostic
(function() {
  console.log('=== Tracking Diagnostic ===');

  console.log('GA4 Status:', typeof gtag === 'function' ? 'Loaded' : 'NOT LOADED');
  console.log('GTM Status:', typeof google_tag_manager !== 'undefined' ? 'Loaded' : 'NOT LOADED');
  console.log('Meta Pixel Status:', typeof fbq === 'function' ? 'Loaded' : 'NOT LOADED');

  console.log('\nData Layer:', window.dataLayer);

  console.log('\nGA4 Measurement ID:');
  if (window.dataLayer) {
    window.dataLayer.forEach(item => {
      if (item[0] === 'config') {
        console.log('  ', item[1]);
      }
    });
  }

  console.log('\nCookies:');
  console.log('  _ga:', document.cookie.indexOf('_ga') !== -1 ? 'Present' : 'Missing');
  console.log('  _gid:', document.cookie.indexOf('_gid') !== -1 ? 'Present' : 'Missing');
  console.log('  _fbp:', document.cookie.indexOf('_fbp') !== -1 ? 'Present' : 'Missing');

  console.log('\n=== End Diagnostic ===');
})();

Testing Checklist

  • Test in view mode (not edit mode)
  • Test after clearing cache
  • Test with ad blockers disabled
  • Check browser console for errors
  • Check Network tab for requests
  • Test on multiple browsers
  • Test on mobile devices
  • Use tag assistant/helper extensions
  • Check real-time analytics reports
  • Verify in GTM debug mode (if using GTM)

When to Escalate

Contact support if:

  1. All checks passed but events still not appearing

    • Tags load correctly
    • No console errors
    • Network requests succeed
    • Tag assistants confirm
    • Still no data in analytics
  2. Episerver-specific integration issues

    • Commerce events not working
    • Content Delivery API issues
    • Multi-site configuration problems
  3. Analytics platform issues

    • GA4 property configuration
    • GTM workspace issues
    • Meta Pixel account problems

Additional Resources

Episerver Resources

Analytics Resources

Tools