How to Fix Umbraco Tracking Events Not Firing | OpsBlu Docs

How to Fix Umbraco Tracking Events Not Firing

Fix GA4, GTM, and pixel events not firing on Umbraco — Razor layout template injection, .NET output caching, and IIS configuration debugging with DevTools

When tracking events fail to fire on your Umbraco site, systematic debugging is essential. This guide covers .NET-specific debugging, browser DevTools usage, IIS configuration issues, and Umbraco-specific troubleshooting for GA4, GTM, and Meta Pixel.

Common Symptoms

  • Events not appearing in Google Analytics Realtime
  • GTM Preview Mode shows no tags firing
  • Meta Pixel Helper shows no events
  • Browser console shows tracking errors
  • Data layer not populated
  • Tracking scripts not loading

Debugging Strategy

Step 1: Verify Tracking Code Installation

Check Razor view includes tracking:

@* In Master.cshtml or _Layout.cshtml *@
<!DOCTYPE html>
<html>
<head>
    @* Should include GTM or GA4 *@
    @await Html.PartialAsync("~/Views/Partials/Analytics/GoogleTagManager.cshtml")
</head>
<body>
    @* Should include GTM noscript *@
    @await Html.PartialAsync("~/Views/Partials/Analytics/GoogleTagManagerNoScript.cshtml")

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

Verify in browser:

  1. Open your Umbraco site
  2. View page source (Ctrl+U)
  3. Search for tracking IDs:
    • GA4: G-XXXXXXXXXX
    • GTM: GTM-XXXXXXX
    • Meta Pixel: Your 16-digit Pixel ID
  4. Verify scripts are present

Step 2: Check Browser Console

  1. Open DevTools (F12)
  2. Click Console tab
  3. Look for JavaScript errors
  4. Common errors:
    Uncaught ReferenceError: gtag is not defined
    Uncaught ReferenceError: dataLayer is not defined
    Uncaught ReferenceError: fbq is not defined
    

Step 3: Verify Network Requests

  1. Open DevTools → Network tab
  2. Filter by google-analytics.com or googletagmanager.com
  3. Reload page
  4. Verify requests are sent:
    • GA4: collect endpoint
    • GTM: gtm.js script
    • Meta Pixel: facebook.com/tr endpoint

GA4-Specific Debugging

Check GA4 Installation

Verify gtag function exists:

<script>
    // Debug GA4
    window.addEventListener('load', function() {
        if (typeof gtag === 'function') {
            console.log('✓ GA4 gtag function exists');

            // Check data layer
            console.log('Data Layer:', window.dataLayer);
        } else {
            console.error('✗ GA4 gtag function not found');
        }
    });
</script>

Enable GA4 Debug Mode

In Razor view:

@inject Microsoft.Extensions.Hosting.IHostEnvironment HostEnvironment

<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());

    gtag('config', 'G-XXXXXXXXXX', {
        @if (HostEnvironment.IsDevelopment())
        {
            <text>
            'debug_mode': true,
            </text>
        }
        'send_page_view': true
    });

    @if (HostEnvironment.IsDevelopment())
    {
        <text>
        // Log all gtag calls
        var originalGtag = window.gtag;
        window.gtag = function() {
            console.log('GA4 Event:', arguments);
            return originalGtag.apply(this, arguments);
        };
        </text>
    }
</script>

Test GA4 Events

Manual event firing:

// In browser console
gtag('event', 'test_event', {
    'event_category': 'test',
    'event_label': 'manual_test'
});

Then check Google Analytics → Realtime → Events for test_event.

Common GA4 Issues

Issue: gtag not defined

Cause: Script not loaded or blocked Solution:

<script>
    // Wait for gtag to load
    function waitForGtag(callback) {
        if (typeof gtag !== 'undefined') {
            callback();
        } else {
            setTimeout(function() { waitForGtag(callback); }, 100);
        }
    }

    waitForGtag(function() {
        console.log('GA4 ready');
        gtag('event', 'page_view');
    });
</script>

Issue: Events not showing in Realtime

Cause: Wrong Measurement ID or property Solution:

@inject IConfiguration Configuration

@{
    var gaId = Configuration["Analytics:GoogleAnalytics:MeasurementId"];
    if (string.IsNullOrEmpty(gaId))
    {
        throw new Exception("GA4 Measurement ID not configured");
    }
}

<script>
    console.log('Using GA4 ID:', '@gaId');
    gtag('config', '@gaId');
</script>

GTM-Specific Debugging

Check GTM Installation

Verify dataLayer exists:

// In browser console
console.log(dataLayer);
console.log(google_tag_manager);

Should output arrays/objects, not undefined.

Use GTM Preview Mode

  1. Log in to Google Tag Manager
  2. Click Preview button
  3. Enter your Umbraco site URL
  4. GTM Debug panel opens
  5. Navigate site and verify:
    • Tags fire correctly
    • Variables populate
    • Triggers activate

Debug Data Layer

Log all data layer pushes:

@inject Microsoft.Extensions.Hosting.IHostEnvironment HostEnvironment

@if (HostEnvironment.IsDevelopment())
{
    <script>
        // Initialize data layer with logging
        window.dataLayer = window.dataLayer || [];

        var originalPush = window.dataLayer.push;
        window.dataLayer.push = function() {
            console.log('Data Layer Push:', arguments);
            return originalPush.apply(window.dataLayer, arguments);
        };
    </script>
}

Common GTM Issues

Issue: GTM container not loading

Cause: Incorrect Container ID or CSP blocking Solution:

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

Issue: Data layer not initialized before GTM

Cause: Wrong script order Solution:

<!-- Initialize data layer FIRST -->
<script>
    window.dataLayer = window.dataLayer || [];
    dataLayer.push({
        'pageType': '@Model?.ContentType.Alias'
    });
</script>

<!-- THEN load GTM -->
<script>
    (function(w,d,s,l,i){/* GTM script */})(window,document,'script','dataLayer','GTM-XXXXXXX');
</script>

Meta Pixel Debugging

Check Meta Pixel Installation

Verify fbq function:

// In browser console
console.log(typeof fbq);
// Should output: "function"

console.log(fbq.version);
// Should output: "2.0"

Use Meta Pixel Helper

  1. Install Meta Pixel Helper Chrome extension
  2. Navigate to your Umbraco site
  3. Click extension icon
  4. Verify:
    • Pixel detected
    • Events firing
    • No errors

Debug Meta Pixel Events

Enable console logging:

@inject Microsoft.Extensions.Hosting.IHostEnvironment HostEnvironment

<script>
    !function(f,b,e,v,n,t,s) {/* Meta Pixel base code */}(window, document,'script','https://connect.facebook.net/en_US/fbevents.js');

    fbq('init', 'YOUR_PIXEL_ID');

    @if (HostEnvironment.IsDevelopment())
    {
        <text>
        // Log all fbq calls
        var originalFbq = window.fbq;
        window.fbq = function() {
            console.log('Meta Pixel Event:', arguments);
            return originalFbq.apply(this, arguments);
        };
        </text>
    }

    fbq('track', 'PageView');
</script>

Common Meta Pixel Issues

Issue: fbq not defined

Cause: Script blocked by ad blocker or CSP Solution:

<script>
    // Check if fbq exists before calling
    if (typeof fbq === 'function') {
        fbq('track', 'PageView');
    } else {
        console.warn('Meta Pixel blocked or not loaded');
    }
</script>

Umbraco-Specific Issues

Umbraco Cache Preventing Updates

Issue: Code changes not reflected Solution:

# Clear Umbraco cache
Remove-Item -Path "App_Data\TEMP\*" -Recurse -Force
Remove-Item -Path "App_Data\NuCache\*" -Recurse -Force

# Rebuild Examine indexes
# Navigate to Umbraco Backoffice → Settings → Examine Management → Rebuild all indexes

Or via code:

using Umbraco.Cms.Core.Cache;

public class CacheClearer
{
    private readonly AppCaches _appCaches;

    public CacheClearer(AppCaches appCaches)
    {
        _appCaches = appCaches;
    }

    public void ClearAll()
    {
        _appCaches.RuntimeCache.Clear();
        _appCaches.RequestCache.Clear();
    }
}

Partial View Not Rendering

Issue: Tracking partial not included Debug:

@* Add debug output *@
@{
    var partialPath = "~/Views/Partials/Analytics/GoogleTagManager.cshtml";
}

<!-- Attempting to render: @partialPath -->

@try
{
    @await Html.PartialAsync(partialPath)
    <!-- ✓ Partial rendered successfully -->
}
catch (Exception ex)
{
    <!-- ✗ Error rendering partial: @ex.Message -->
}

Configuration Not Loading

Issue: appsettings.json values not accessible Debug:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

public class ConfigDebugger
{
    private readonly IConfiguration _configuration;
    private readonly ILogger<ConfigDebugger> _logger;

    public ConfigDebugger(IConfiguration configuration, ILogger<ConfigDebugger> logger)
    {
        _configuration = configuration;
        _logger = logger;
    }

    public void LogConfiguration()
    {
        var gaId = _configuration["Analytics:GoogleAnalytics:MeasurementId"];
        var gtmId = _configuration["Analytics:GoogleTagManager:ContainerId"];

        _logger.LogInformation($"GA4 ID: {gaId ?? "NOT SET"}");
        _logger.LogInformation($"GTM ID: {gtmId ?? "NOT SET"}");
    }
}

In Razor:

@inject IConfiguration Configuration
@inject ILogger<RazorPage> Logger

@{
    var gaId = Configuration["Analytics:GoogleAnalytics:MeasurementId"];

    if (string.IsNullOrEmpty(gaId))
    {
        Logger.LogWarning("GA4 Measurement ID not configured in appsettings.json");
    }
    else
    {
        Logger.LogInformation($"Using GA4 ID: {gaId}");
    }
}

IIS-Specific Issues

URL Rewrite Interfering

Issue: IIS URL Rewrite blocking tracking scripts Check Web.config:

<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <!-- Ensure tracking scripts not blocked -->
        <rule name="Allow Tracking Scripts" stopProcessing="true">
          <match url="^(gtag|gtm|fbevents)\.js$" />
          <action type="None" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

HTTPS/SSL Issues

Issue: Mixed content blocking tracking on HTTPS Solution:

<configuration>
  <system.webServer>
    <rewrite>
      <outboundRules>
        <rule name="Upgrade tracking to HTTPS">
          <match filterByTags="Script"
                 pattern="http://(www\.google-analytics\.com|www\.googletagmanager\.com|connect\.facebook\.net)" />
          <action type="Rewrite"
                  value="https://{R:1}" />
        </rule>
      </outboundRules>
    </rewrite>
  </system.webServer>
</configuration>

Application Pool Recycling

Issue: Tracking breaks after app pool recycle Solution:

<!-- In Web.config -->
<configuration>
  <system.webServer>
    <serverRuntime enabled="true" />
  </system.webServer>

  <system.web>
    <compilation debug="false" targetFramework="net6.0" />
    <httpRuntime targetFramework="net6.0" enableVersionHeader="false" />
  </system.web>
</configuration>

Debugging Tools and Extensions

Browser Extensions

  1. Google Tag Assistant - Verify GA4 and GTM
  2. Meta Pixel Helper - Debug Meta Pixel
  3. Web Vitals - Monitor performance
  4. EditThisCookie - Check tracking cookies

.NET Debugging

Add comprehensive logging:

using Microsoft.Extensions.Logging;

public class TrackingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<TrackingMiddleware> _logger;

    public TrackingMiddleware(RequestDelegate next, ILogger<TrackingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation($"Request URL: {context.Request.Path}");
        _logger.LogInformation($"User Agent: {context.Request.Headers["User-Agent"]}");

        await _next(context);
    }
}

Network Inspection

Check tracking requests:

// In browser console
performance.getEntriesByType('resource')
    .filter(r => r.name.includes('google-analytics') ||
                 r.name.includes('googletagmanager') ||
                 r.name.includes('facebook'))
    .forEach(r => console.log(r.name, r.responseStatus));

Systematic Debugging Checklist

  • Tracking code present in page source
  • No JavaScript errors in console
  • Network requests to tracking domains successful
  • Tracking functions (gtag/fbq) defined
  • Data layer initialized (for GTM)
  • Configuration values loaded correctly
  • Umbraco cache cleared
  • IIS/Web.config not blocking scripts
  • CSP headers allow tracking domains
  • HTTPS/SSL configured correctly
  • Ad blockers disabled for testing
  • Cookies enabled in browser

Next Steps