Google Analytics 4 Setup on Ghost | OpsBlu Docs

Google Analytics 4 Setup on Ghost

Step-by-step GA4 installation and configuration guide for Ghost. Covers measurement ID setup, data stream configuration, and platform-specific.

Ghost provides multiple methods to implement Google Analytics 4, each suited to different technical requirements and hosting configurations. This guide covers both code injection (easiest) and custom theme integration (most control).

Prerequisites

Before implementing GA4 on Ghost:

  • GA4 Property Created - Set up your GA4 property in Google Analytics
  • Measurement ID - Obtain your GA4 measurement ID (format: G-XXXXXXXXXX)
  • Ghost Admin Access - Owner or Administrator role required for code injection
  • Theme Access - Self-hosted Ghost or ability to upload custom themes (for theme method)

Code injection is the fastest way to add GA4 without modifying theme files. Changes survive theme updates and work on both Ghost(Pro) and self-hosted installations.

Step 1: Access Code Injection

  1. Log in to Ghost Admin (yourdomain.com/ghost)
  2. Navigate to Settings → Code Injection
  3. Locate the Site Header section

Step 2: Add GA4 Tracking Code

Paste the following code in the Site Header field:

<!-- Google Analytics 4 -->
<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');
</script>

Replace G-XXXXXXXXXX with your actual GA4 measurement ID.

Step 3: Save and Verify

  1. Click Save in the top-right corner
  2. Open your Ghost site in a new browser tab
  3. Use Google Tag Assistant or GA Debugger browser extension to verify tracking
  4. Check Google Analytics → Realtime to see active users

Enhanced Code Injection with Ghost Data

For better tracking context, include Ghost-specific metadata:

<!-- Google Analytics 4 with Ghost Metadata -->
<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());

  // Configure GA4 with Ghost context
  gtag('config', 'G-XXXXXXXXXX', {
    'custom_map': {
      'dimension1': 'ghost_content_type',
      'dimension2': 'ghost_member_status'
    }
  });

  // Set Ghost-specific dimensions
  {{#post}}
  gtag('event', 'page_view', {
    'ghost_content_type': 'post',
    'ghost_post_id': '{{id}}',
    'ghost_author': '{{primary_author.name}}'
  });
  {{/post}}

  {{#page}}
  gtag('event', 'page_view', {
    'ghost_content_type': 'page'
  });
  {{/page}}

  {{#is "home"}}
  gtag('event', 'page_view', {
    'ghost_content_type': 'home'
  });
  {{/is}}

  {{#member}}
  gtag('set', 'user_properties', {
    'ghost_member_status': 'member'
  });
  {{/member}}
</script>

Note: Code injection has limited Handlebars support. For full dynamic tracking, use the custom theme method.

Method 2: Custom Theme Integration

For maximum control and access to all Ghost Handlebars helpers, integrate GA4 directly into your theme.

Step 1: Download Your Theme

For Ghost(Pro):

  1. Navigate to Settings → Design
  2. Scroll to Installed Themes
  3. Click Download next to your active theme

For Self-Hosted:

cd /var/www/ghost/content/themes/
cp -r your-theme-name your-theme-name-ga4

Step 2: Create Analytics Partial

Create a new file: partials/analytics.hbs in your theme directory:

{{!-- partials/analytics.hbs --}}
<!-- Google Analytics 4 -->
<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());

  // Base configuration
  gtag('config', 'G-XXXXXXXXXX', {
    'send_page_view': false, // We'll send custom page_view events
    'custom_map': {
      'dimension1': 'content_type',
      'dimension2': 'author_name',
      'dimension3': 'member_status',
      'dimension4': 'visibility',
      'dimension5': 'primary_tag'
    }
  });

  // Build custom page_view event with Ghost data
  var pageData = {
    'page_title': '{{meta_title}}',
    'page_location': '{{@site.url}}{{url}}',
    'content_type': '{{#is "post"}}post{{/is}}{{#is "page"}}page{{/is}}{{#is "home"}}home{{/is}}{{#is "tag"}}tag{{/is}}{{#is "author"}}author{{/is}}',
    {{#post}}
    'author_name': '{{primary_author.name}}',
    'visibility': '{{visibility}}',
    'published_date': '{{published_at}}',
    {{#primary_tag}}
    'primary_tag': '{{name}}',
    {{/primary_tag}}
    {{/post}}
    {{#member}}
    'member_status': 'member',
    'member_uuid': '{{uuid}}',
    {{/member}}
    {{^member}}
    'member_status': 'visitor',
    {{/member}}
  };

  // Send enhanced page_view
  gtag('event', 'page_view', pageData);
</script>

Step 3: Include Partial in Theme

Edit default.hbs and add the partial before \{\{ghost_head\}\}:

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{meta_title}}</title>

    {{!-- Google Analytics --}}
    {{> analytics}}

    {{ghost_head}}
</head>

Step 4: Upload and Activate Theme

For Ghost(Pro):

  1. Zip your modified theme directory
  2. Navigate to Settings → Design → Change theme
  3. Upload the ZIP file
  4. Click Activate next to your uploaded theme

For Self-Hosted:

# Restart Ghost to load theme changes
ghost restart

Then activate via Ghost Admin → Settings → Design.

Step 5: Verify Installation

  1. Open your Ghost site
  2. Open browser DevTools → Console
  3. Look for GA4 debug messages (if using GA Debugger extension)
  4. Check Google Analytics → Realtime → Overview
  5. Verify custom dimensions appear in GA4 (may take 24-48 hours)

Performance Optimization

Preconnect to GA4 Domains

Add to your theme's <head> section (before analytics partial):

<link rel="preconnect" href="https://www.google-analytics.com">
<link rel="preconnect" href="https://www.googletagmanager.com">

Defer Loading for Non-Critical Tracking

<!-- Defer GA4 until after page load -->
<script>
  window.addEventListener('load', function() {
    var script = document.createElement('script');
    script.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX';
    script.async = true;
    document.head.appendChild(script);

    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
    gtag('config', 'G-XXXXXXXXXX');
  });
</script>

Conditional Loading by Content Type

Only load GA4 on specific content types:

{{!-- Only track posts and pages, not admin or RSS --}}
{{#is "post, page"}}
  {{> analytics}}
{{/is}}

Ghost Members Integration

Track member status and subscription tier:

<script>
  {{#if @member}}
  // Member-specific tracking
  gtag('set', 'user_properties', {
    'member_status': '{{#if @member.paid}}paid{{else}}free{{/if}}',
    'member_created': '{{@member.created_at}}',
    {{#if @member.subscriptions}}
    'subscription_tier': '{{@member.subscriptions.[0].tier.name}}',
    {{/if}}
  });
  {{else}}
  // Visitor tracking
  gtag('set', 'user_properties', {
    'member_status': 'visitor'
  });
  {{/if}}
</script>

Ghost(Pro) vs. Self-Hosted Considerations

Ghost(Pro)

  • Code Injection: Full support, easiest method
  • Theme Integration: Requires theme upload via Admin
  • CDN: Cloudflare caching may delay tracking updates (usually not an issue)
  • SSL: Automatic HTTPS (GA4 requires secure sites)

Self-Hosted

  • File Access: Direct theme editing in /content/themes/
  • Server-Side Tracking: Can implement GA4 Measurement Protocol
  • Caching: Configure Nginx/Varnish to exclude tracking scripts
  • Performance: Full control over async/defer strategies

Validation and Testing

Real-Time Testing

  1. Open Google Analytics → Realtime → Overview
  2. Visit your Ghost site in incognito mode
  3. Navigate between posts and pages
  4. Verify events appear in real-time report

Debug Mode

Add debug_mode to GA4 configuration:

gtag('config', 'G-XXXXXXXXXX', {
  'debug_mode': true
});

Open browser DevTools → Console to see detailed event logging.

Tag Assistant

Install Google Tag Assistant Chrome extension:

  1. Click extension icon on your Ghost site
  2. Verify GA4 tag fires on page load
  3. Check for errors or warnings
  4. Review enhanced measurement events

Common Issues

GA4 Not Tracking

  • Verify Measurement ID - Check for typos in G-XXXXXXXXXX
  • Ad Blockers - Test in incognito without extensions
  • Code Placement - Ensure script is in <head> before \{\{ghost_head\}\}
  • Caching - Clear Ghost cache or wait 5-10 minutes for CDN refresh

Duplicate Tracking

  • Code Injection + Theme - Remove one implementation
  • Multiple GA4 Tags - Search theme for duplicate gtag calls
  • GTM Conflict - Don't use both GTM and direct GA4 implementation

Member Data Not Tracking

  • Members Disabled - Ensure Ghost Members feature is enabled (Settings → Membership)
  • Context Issues - \{\{@member\}\} only works in theme, not code injection
  • Cache Problems - Member context may be cached; test with different browsers

Performance Impact

  • Too Many Events - Limit custom events in theme
  • Synchronous Loading - Use async attribute on GA4 script
  • Large Data Layers - Keep custom dimensions minimal

Next Steps