How to Fix Ghost Tracking Events Not Firing | OpsBlu Docs

How to Fix Ghost Tracking Events Not Firing

Fix GA4, GTM, and pixel events not firing on Ghost — code injection placement, Ghost Portal event conflicts, and member-context tracking debugging

Tracking failures on Ghost sites often stem from code injection issues, cache problems, member context limitations, and Ghost Portal event listener conflicts. This guide provides systematic debugging for GA4, Meta Pixel, GTM, and Ghost-specific tracking issues.

Common Symptoms

  • Events don't appear in GA4 Realtime or DebugView
  • Meta Pixel Helper shows no pixel or no events
  • GTM Preview Mode shows tags not firing
  • Member signup/login events missing
  • Portal events not triggering
  • Data layer variables undefined
  • Duplicate events firing

Systematic Debugging Approach

Step 1: Verify Tracking Code Exists

Check if tracking code is present in page source.

View Page Source

  1. Navigate to your Ghost site
  2. Right-clickView Page Source (or Ctrl+U)
  3. Search for tracking code (Ctrl+F):
    • GA4: Search for gtag or G-XXXXXXXXXX
    • Meta Pixel: Search for fbq or your pixel ID
    • GTM: Search for GTM-XXXXXXX

If not found:

  • Check Ghost Admin → Settings → Code Injection
  • Verify theme includes tracking partials
  • Clear Ghost cache (self-hosted: ghost restart)

Check Browser DevTools

  1. Open DevTools (F12)
  2. Click Console tab
  3. Type and enter:
// Check if tracking functions exist
console.log('gtag:', typeof gtag);        // Should be "function"
console.log('fbq:', typeof fbq);          // Should be "function"
console.log('dataLayer:', typeof dataLayer); // Should be "object"

// Check if they're defined
console.log(window.gtag);
console.log(window.fbq);
console.log(window.dataLayer);

If undefined:

  • Script didn't load or has syntax errors
  • Check Network tab for failed requests
  • Review Console for JavaScript errors

Step 2: Check Network Requests

Verify tracking requests are sent to analytics servers.

Monitor Network Traffic

  1. Open DevTools → Network tab
  2. Reload page
  3. Filter by:
    • GA4: google-analytics.com or analytics.google.com
    • Meta Pixel: facebook.net or connect.facebook.net
    • GTM: googletagmanager.com

Look for:

  • Requests with 200 status (successful)
  • Requests with 4xx/5xx status (errors)
  • No requests at all (script blocked or not loading)

Common Issues:

  • Ad Blockers - Disable and retest
  • Browser Extensions - Test in incognito
  • Corporate Firewalls - Test on different network
  • CORS Errors - Check console for cross-origin errors

Step 3: Test in Isolation

Remove potential conflicts by testing in controlled environments.

Incognito Mode

  1. Open incognito/private browsing window
  2. Navigate to your Ghost site
  3. Test tracking again

Why this helps:

  • Disables browser extensions (ad blockers, etc.)
  • Fresh session (no cached scripts)
  • No cookies from previous sessions

Different Browsers

Test in multiple browsers:

  • Chrome (GA4/Meta Pixel work best)
  • Firefox
  • Safari (ITP may block some tracking)
  • Edge

Disable Code Injection Temporarily

In Ghost Admin → Settings → Code Injection:

  1. Comment out all code injection
  2. Save and test theme-based tracking only
  3. Or vice versa

Step 4: Check Ghost-Specific Issues

Ghost has unique tracking challenges related to caching, members, and Portal.

Ghost Cache Issues

Ghost(Pro):

Ghost(Pro) uses Cloudflare CDN which caches pages.
Wait 5-10 minutes after making tracking changes.
Or use query parameter to bypass cache:
https://yoursite.com/?nocache=1

Self-Hosted:

# Restart Ghost to clear cache
ghost restart

# If using Redis
redis-cli FLUSHALL

# If using Varnish
varnishadm ban req.url "~" "."

# If using Nginx caching
rm -rf /var/cache/nginx/*
nginx -s reload

Member Context Issues

Problem: \{\{@member\}\} data not available in code injection

<!-- Code Injection has limited Handlebars support -->
<!-- This WON'T work reliably in code injection: -->
<script>
  {{#member}}
  var memberEmail = '{{email}}'; // May be undefined
  {{/member}}
</script>

Solution: Move to custom theme for full member access

{{!-- In default.hbs or post.hbs --}}
<script>
  {{#member}}
  var memberData = {
    email: '{{email}}',
    uuid: '{{uuid}}',
    paid: {{#if paid}}true{{else}}false{{/if}}
  };
  console.log('Member:', memberData);
  {{/member}}
</script>

Ghost Portal Event Tracking Issues

Issue: Portal Events Not Firing

Symptoms:

  • portal-signup, portal-signin events not triggering
  • Event listeners not catching Portal actions
  • Member signups not tracked

Debug Portal Events:

// Add to Ghost theme to test Portal events
window.addEventListener('portal-ready', function() {
  console.log('Ghost Portal is ready');
});

window.addEventListener('portal-open', function() {
  console.log('Portal opened');
});

window.addEventListener('portal-close', function() {
  console.log('Portal closed');
});

window.addEventListener('portal-signup', function(event) {
  console.log('Member signed up:', event);
});

window.addEventListener('portal-signin', function(event) {
  console.log('Member signed in:', event);
});

// Listen for ALL events to debug
window.addEventListener('message', function(event) {
  if (event.data && event.data.type) {
    console.log('Portal event:', event.data.type, event.data);
  }
});

Common Problems:

  1. Event Listeners Added Too Late
// Bad: May miss early events
window.addEventListener('load', function() {
  window.addEventListener('portal-signup', handler); // Too late!
});

// Good: Add listeners immediately
window.addEventListener('portal-signup', function() {
  // Handle signup
});
  1. Multiple Listeners Causing Duplicates
// Bad: Adds listener every page load
window.addEventListener('portal-signup', handler);

// Good: Add once with { once: true }
window.addEventListener('portal-signup', handler, { once: true });

// Or check if already added
if (!window._portalListenersAdded) {
  window.addEventListener('portal-signup', handler);
  window._portalListenersAdded = true;
}
  1. Portal Not Initialized
// Check if Portal exists
console.log('Ghost Portal:', window.ghost);

// Verify Portal script loaded
console.log('Portal script:', document.querySelector('script[src*="portal"]'));

Issue: Portal Tracking Fires Multiple Times

Problem: Duplicate tracking events for single action

Solution:

// Track only once per session
window.addEventListener('portal-signup', function() {
  if (!sessionStorage.getItem('signup_tracked')) {
    // Track signup event
    if (typeof gtag !== 'undefined') {
      gtag('event', 'sign_up', {
        method: 'ghost_portal'
      });
    }
    sessionStorage.setItem('signup_tracked', 'true');
  }
});

GA4-Specific Issues

Issue: GA4 Not Tracking Page Views

Debug Checklist:

// 1. Verify gtag function exists
console.log(typeof gtag);
// Expected: "function"

// 2. Check measurement ID
console.log('Searching for: G-');
// View source and verify correct measurement ID

// 3. Manually trigger test event
gtag('event', 'test_event', {
  test_parameter: 'test_value'
});
// Check GA4 DebugView for this event

// 4. Check dataLayer
console.log(window.dataLayer);
// Should show array of events

Common GA4 Problems:

  1. Wrong Measurement ID
// Verify in page source
gtag('config', 'G-XXXXXXXXXX'); // Check this matches your property
  1. Ad Blockers
Test in incognito without extensions.
Ad blockers commonly block google-analytics.com.
  1. Consent Mode Blocking
// Check if consent mode is blocking
gtag('consent', 'default', {
  'analytics_storage': 'granted'
});
  1. Debug Mode Not Enabled
// Enable debug mode to see events in console
gtag('config', 'G-XXXXXXXXXX', {
  'debug_mode': true
});

Issue: GA4 Custom Events Not Recording

Test Event Manually:

// Try firing event manually in console
gtag('event', 'custom_event_name', {
  'parameter1': 'value1',
  'parameter2': 'value2'
});

// Check GA4 DebugView (Admin → DebugView)
// Event should appear within seconds

Common Problems:

  1. Event Name Invalid
// Bad: Spaces, special characters
gtag('event', 'Member Sign Up!');

// Good: Underscores, lowercase
gtag('event', 'member_signup');
  1. Too Many Parameters
// GA4 limits: 25 custom parameters per event
// Reduce number of parameters
  1. Parameter Values Too Long
// Parameter values limited to 100 characters
// Truncate long values

GTM-Specific Issues

Issue: GTM Container Not Loading

Debug GTM:

// 1. Check if dataLayer exists
console.log(window.dataLayer);
// Expected: Array with GTM events

// 2. Check GTM container loaded
console.log(google_tag_manager);
// Should show GTM container object

// 3. Verify container ID
// View source and search for: GTM-

Common GTM Problems:

  1. Container Not Published
GTM changes must be PUBLISHED, not just saved.
Check GTM workspace status.
  1. Wrong Container ID
// Verify in page source
GTM-XXXXXXX // Must match your container
  1. dataLayer Defined After GTM
// Bad: dataLayer defined after GTM script
<script>window.dataLayer = [];</script>
<script src="gtm.js"></script> <!-- GTM sees empty dataLayer -->

// Good: dataLayer before GTM
<script>window.dataLayer = [{...}];</script>
<script src="gtm.js"></script>

Issue: GTM Tags Not Firing

Use GTM Preview Mode to debug:

  1. In GTM, click Preview button
  2. Enter your Ghost site URL
  3. Click Connect
  4. New window opens with Tag Assistant
  5. Navigate site and observe:
    • Tags Fired - Successful
    • Tags Not Fired - Check triggers
    • Errors - Review tag configuration

Common Tag Issues:

  1. Trigger Conditions Wrong
Tag fires on: Some Page Views
Condition: Page Path contains /blog/

If tag doesn't fire, check if condition matches.
Use "All Pages" trigger to test.
  1. Variables Undefined
// In Tag Assistant, check Variables tab
// Ensure custom variables populate correctly

// Test in console:
console.log(dataLayer);
console.log(dataLayer[0].postTitle); // Should have value
  1. Tag Blocked by Exception
Check GTM for Blocking Triggers on the tag.
Ensure exception conditions aren't preventing firing.

Issue: Data Layer Variables Not Populating

Debug Data Layer:

// 1. Check if ghost_data_ready event fired
console.log(dataLayer.filter(e => e.event === 'ghost_data_ready'));

// 2. Inspect data layer structure
console.log(JSON.stringify(dataLayer, null, 2));

// 3. Check specific variables
console.log(dataLayer[0].post);
console.log(dataLayer[0].member);
console.log(dataLayer[0].site);

Common Data Layer Problems:

  1. Handlebars Syntax Errors
{{!-- Bad: Missing closing tag --}}
{{#post}}
  'postTitle': '{{title}}'
{{/if}}  <!-- Wrong closing tag! Should be /post -->

{{!-- Good: Correct syntax --}}
{{#post}}
  'postTitle': '{{title}}'
{{/post}}
  1. JSON Syntax Errors
// Bad: Trailing comma
dataLayer.push({
  'post': {
    'title': 'Hello',
  }, // Trailing comma breaks JSON
});

// Good: No trailing commas
dataLayer.push({
  'post': {
    'title': 'Hello'
  }
});
  1. Member Context in Code Injection
// Code injection has limited member access
// Move data layer to theme for full {{@member}} support

Meta Pixel Issues

Issue: Meta Pixel Not Loading

Debug Meta Pixel:

// 1. Check if fbq exists
console.log(typeof fbq);
// Expected: "function"

// 2. Check pixel version
console.log(fbq.version);
// Expected: "2.0"

// 3. Check pixel initialized
console.log(window._fbq);
// Should show pixel object

// 4. Manually trigger test event
fbq('track', 'PageView');

Use Meta Pixel Helper:

  1. Install Meta Pixel Helper extension
  2. Navigate to your Ghost site
  3. Click extension icon
  4. Should show:
    • Green checkmark - Pixel working
    • Yellow warning - Issues detected
    • Red X - Pixel not found

Issue: Meta Events Not Tracking

Test Event Manually:

// Fire test event in console
fbq('track', 'Lead', {
  content_name: 'Test Lead'
});

// Check Meta Events Manager → Test Events
// Should appear within seconds

Common Meta Pixel Problems:

  1. Wrong Pixel ID
// Verify pixel ID in page source
fbq('init', '1234567890'); // Must match your pixel
  1. Event Name Misspelled
// Standard events are case-sensitive
fbq('track', 'purchase');  // Wrong - lowercase
fbq('track', 'Purchase');  // Correct
  1. iOS 14+ Tracking Limitations
- Domain must be verified in Meta Business Suite
- Configure Aggregated Event Measurement
- Implement Conversion API for server-side tracking

Ghost Handlebars Debugging

Issue: Handlebars Helpers Not Working

Test Helper Output:

{{!-- Debug helpers in theme --}}
<script>
  console.log('Site title:', '{{@site.title}}');
  console.log('Post context:', '{{#post}}true{{else}}false{{/post}}');
  console.log('Member context:', '{{#member}}true{{else}}false{{/member}}');
</script>

Common Handlebars Issues:

  1. Wrong Context
{{!-- Bad: Using @post instead of post --}}
{{@post.title}}  <!-- Undefined -->

{{!-- Good: Correct helper --}}
{{post.title}}   <!-- Works -->
  1. Helper Not Available in Code Injection
{{!-- Limited Handlebars in code injection --}}
{{!-- Move complex helpers to theme --}}
  1. Ghost Version Compatibility
{{!-- Ghost 5.x changed member subscriptions --}}
{{!-- Old (Ghost 4): --}}
{{@member.subscription.tier.name}}

{{!-- New (Ghost 5): --}}
{{@member.subscriptions.[0].tier.name}}

Performance Impact on Tracking

Issue: Tracking Delayed by Slow Page Load

If your site is slow, tracking may not initialize:

// Ensure tracking loads even if page is slow
window.addEventListener('DOMContentLoaded', function() {
  // Initialize critical tracking here
  // Don't wait for full page load
});

Testing Tools Summary

Browser DevTools

  • Console: Check for errors, test functions
  • Network: Monitor tracking requests
  • Application: Check cookies and storage

Analytics Platform Tools

  • GA4 DebugView: Real-time event monitoring
  • Meta Pixel Helper: Pixel status and events
  • GTM Preview Mode: Tag firing debugging
  • Google Tag Assistant: Tag validation

Third-Party Tools

  • ObservePoint: Automated tag auditing
  • Tag Inspector: Real-time tag monitoring
  • dataLayer Checker: GTM data layer inspector

Next Steps