Install Google Analytics 4 on HubSpot | Blue Frog Docs

Install Google Analytics 4 on HubSpot

How to install GA4 on HubSpot CMS using Site Header HTML, custom modules, or Google Tag Manager.

Install Google Analytics 4 on HubSpot

There are three main methods to install GA4 on your HubSpot CMS Hub site, each with different capabilities and complexity levels.

Method Comparison

Method Difficulty Customization Flexibility Recommended For
Site Header HTML Easy Medium Low Quick setup, all pages
Google Tag Manager Medium High High Most sites (recommended)
Custom Module Advanced High Medium Page-specific tracking

Method 1: Site Header HTML (Easiest)

Add GA4 globally to all HubSpot pages using the Site Header HTML setting.

Setup Steps

  1. Get Your GA4 Measurement ID

    • Open Google Analytics 4
    • Go to AdminData Streams
    • Click your web data stream
    • Copy your Measurement ID (format: G-XXXXXXXXXX)
  2. Access Site Header Settings

    • In HubSpot, go to Settings (gear icon)
    • Navigate to WebsitePages
    • Scroll to Site Header HTML
  3. Add GA4 Tracking Code

    Paste this code into the Site Header HTML box:

    <!-- 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', {
        'send_page_view': true,
        'cookie_flags': 'SameSite=None;Secure'
      });
    </script>
    

    Replace G-XXXXXXXXXX with your Measurement ID (appears twice).

  4. Add HubSpot-Specific Parameters (Optional)

    Enhance tracking with HubSpot data:

    <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', {
        'send_page_view': true,
        'cookie_flags': 'SameSite=None;Secure',
        {% if contact.email %}
        'user_id': '{{ contact.vid }}', // HubSpot contact ID
        {% endif %}
        'custom_map': {
          'dimension1': 'lifecycle_stage',
          'dimension2': 'contact_type'
        }
      });
    
      {% if contact %}
      // Send contact properties as user properties
      gtag('set', 'user_properties', {
        'lifecycle_stage': '{{ contact.lifecycle_stage }}',
        'contact_type': '{% if contact.is_contact %}contact{% else %}visitor{% endif %}'
      });
      {% endif %}
    </script>
    
  5. Save Settings

    • Click Save at the bottom of the page
    • Changes apply immediately to all pages

What Gets Tracked (Site Header HTML Method)

Automatically tracked:

  • All page views across your entire site
  • Page titles and URLs
  • Referral sources
  • User demographics (if enabled in GA4)
  • Device and browser information

Requires additional code:

Pros & Cons of Site Header HTML

Pros:

  • Simple, one-time setup
  • Works on all pages automatically
  • No coding knowledge required
  • Easy to maintain

Cons:

  • Cannot exclude specific pages
  • All customization requires updating this one code block
  • HubL variables available but limited
  • Harder to debug than GTM

GTM provides the most flexibility and is recommended for most HubSpot sites.

Why Use GTM?

  • Easier management: Update tracking without editing HubSpot settings
  • Better organization: All tags in one centralized platform
  • Advanced features: Custom events, triggers, variables
  • Team collaboration: Non-technical marketers can update tags
  • Multiple platforms: Add GA4, Meta Pixel, and more through one container

Setup Steps

  1. Install GTM on HubSpot

    See the complete guide: Install Google Tag Manager on HubSpot

  2. Create GA4 Configuration Tag

    Once GTM is installed on your HubSpot site:

    a. Create New Tag

    • In GTM, go to TagsNew
    • Click Tag Configuration

    b. Select Tag Type

    • Choose Google Analytics: GA4 Configuration

    c. Configure Settings

    • Measurement ID: Enter your GA4 Measurement ID (G-XXXXXXXXXX)

    d. Add HubSpot Variables (Optional)

    In Configuration Settings, click Fields to Set:

    Field Name Value
    user_id \{\{Contact ID\}\}
    page_type \{\{Page Type\}\}
    content_group \{\{Content Group\}\}

    You'll need to create these variables first using HubSpot's data layer (see GTM Data Layer).

    e. Set Trigger

    • Triggering: Select All Pages

    f. Save Tag

    • Name it "GA4 - Configuration"
    • Click Save
  3. Create Data Layer Variables for HubSpot Data

    To pass HubSpot-specific data to GA4:

    a. Create Contact ID Variable

    • Go to VariablesNew
    • Choose Data Layer Variable
    • Data Layer Variable Name: contactId
    • Save as "Contact ID"

    b. Create Page Type Variable

    • Create new Data Layer Variable
    • Data Layer Variable Name: pageType
    • Save as "Page Type"

    See HubSpot GTM Data Layer for implementing the data layer in HubSpot.

  4. Test Configuration

    • Click Preview in GTM
    • Visit your HubSpot site
    • Verify "GA4 - Configuration" tag fires on page load
    • Check GA4 Realtime reports
  5. Publish Container

    • Click Submit
    • Add version name: "Added GA4 Configuration"
    • Click Publish

Next Steps with GTM

After GTM and GA4 are set up:

Method 3: Custom Module (Advanced)

Create a reusable GA4 module that can be added to specific templates or pages.

When to Use Custom Module

  • Need different GA4 properties on different sections
  • Want granular control over which pages have GA4
  • Building a multi-site HubSpot setup
  • Require template-specific configurations

Setup Steps

  1. Access Design Tools

    • Go to MarketingFiles and TemplatesDesign Tools
    • Or use local development tools
  2. Create New Module

    • In Design Tools, right-click → New fileNew module
    • Name it "GA4 Tracking Module"
  3. Add Module Code

    In the module's HTML + HubL section:

    {% if module.measurement_id %}
    <!-- Google Analytics 4 -->
    <script async src="https://www.googletagmanager.com/gtag/js?id={{ module.measurement_id }}"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
    
      gtag('config', '{{ module.measurement_id }}', {
        'send_page_view': true,
        {% if module.track_contact_id and contact %}
        'user_id': '{{ contact.vid }}',
        {% endif %}
        {% if module.custom_dimensions %}
        'custom_map': {
          'dimension1': 'lifecycle_stage',
          'dimension2': 'page_type'
        }
        {% endif %}
      });
    
      {% if module.custom_dimensions and contact %}
      gtag('set', 'user_properties', {
        'lifecycle_stage': '{{ contact.lifecycle_stage }}',
        'page_type': '{{ content.type }}'
      });
      {% endif %}
    </script>
    {% endif %}
    
  4. Add Module Fields

    In the module's fields.json or field editor:

    [
      {
        "id": "measurement_id",
        "name": "measurement_id",
        "label": "GA4 Measurement ID",
        "required": true,
        "locked": false,
        "type": "text",
        "default": "G-XXXXXXXXXX"
      },
      {
        "id": "track_contact_id",
        "name": "track_contact_id",
        "label": "Track Contact ID as User ID",
        "required": false,
        "type": "boolean",
        "default": true
      },
      {
        "id": "custom_dimensions",
        "name": "custom_dimensions",
        "label": "Enable Custom Dimensions",
        "required": false,
        "type": "boolean",
        "default": false
      }
    ]
    
  5. Save and Publish Module

  6. Add Module to Template

    In your template (e.g., base.html), add before </head>:

    {% module "ga4_tracking"
      path="@hubspot/ga4_tracking_module",
      measurement_id="G-XXXXXXXXXX",
      track_contact_id=True,
      custom_dimensions=True
    %}
    

Pros & Cons of Custom Module

Pros:

  • Reusable across multiple templates
  • Configurable per-page or per-template
  • Full HubL capabilities
  • Can include conditional logic

Cons:

  • Requires Design Tools access
  • More complex to set up
  • Must be added to each template manually
  • Harder for non-developers to maintain

Integration with HubSpot Native Analytics

Avoiding Duplicate Tracking

HubSpot automatically tracks page views. When adding GA4, you'll have:

  • HubSpot Analytics: Tracks all pages natively
  • GA4: Also tracks all pages

This is expected and acceptable, as:

  • HubSpot Analytics integrates with CRM and marketing tools
  • GA4 provides website behavior and attribution insights
  • Each serves different purposes

Data Discrepancies

Expect minor differences between HubSpot and GA4:

Metric HubSpot GA4
Session definition 30 min inactivity 30 min default (configurable)
User identification Contact-based + anonymous Client ID-based
Bot filtering Automatic Must enable
Referral exclusions Pre-configured Must configure

Best practice: Use each platform for its strengths rather than expecting identical numbers.

Enhanced Configuration Options

IP Anonymization

Anonymize visitor IPs for privacy compliance:

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

Note: GA4 anonymizes IPs by default, but explicit setting ensures compliance.

Cross-Domain Tracking

If your HubSpot site spans multiple domains:

gtag('config', 'G-XXXXXXXXXX', {
  'linker': {
    'domains': ['example.com', 'shop.example.com']
  }
});

Integrate with HubSpot's cookie consent banner:

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

  // Default consent to denied
  gtag('consent', 'default', {
    'analytics_storage': 'denied'
  });

  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');

  // Listen for HubSpot cookie consent
  var _hsq = window._hsq = window._hsq || [];
  _hsq.push(['addPrivacyConsentListener', function(consent) {
    if (consent.allowed) {
      // User accepted - grant consent
      gtag('consent', 'update', {
        'analytics_storage': 'granted'
      });
    }
  }]);
</script>

Verification & Testing

1. Check GA4 Realtime Reports

  • Open GA4 → ReportsRealtime
  • Visit your HubSpot site in another browser tab
  • Verify your visit appears within 30 seconds
  • Navigate to different pages and verify tracking

2. Use GA4 DebugView

Enable debug mode for detailed event inspection:

Add to your GA4 configuration:

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

In GA4:

  • Go to AdminDebugView
  • Visit your site
  • See real-time events with full parameters

3. Verify in Browser DevTools

Check Console:

  • Open browser DevTools (F12)
  • Go to Console tab
  • Reload page
  • Look for GA4-related messages
  • Verify no JavaScript errors

Check Network Tab:

  • Go to Network tab
  • Filter by "collect" or "google-analytics"
  • Reload page
  • Verify requests to google-analytics.com/g/collect
  • Click request to see parameters sent

4. Test with HubSpot Preview

Before publishing changes:

  • Edit any page → Click Preview
  • Open DevTools and verify GA4 loads
  • Check Realtime reports in GA4

Troubleshooting

GA4 Not Loading

Check:

  1. Measurement ID is correct (starts with G-)
  2. No typos in the tracking code
  3. Code is in Site Header HTML (not Site Footer)
  4. Settings have been saved
  5. Browser cache cleared (hard refresh: Ctrl+Shift+R)

Debug:

// Add after gtag config to verify it loaded
console.log('GA4 Loaded:', window.gtag);
console.log('Data Layer:', window.dataLayer);

Events Not Firing

See detailed troubleshooting: Events Not Firing

Quick checks:

  • Verify GA4 base code is installed
  • Check browser console for errors
  • Disable ad blockers for testing
  • Verify you're not filtering your own traffic in GA4

Duplicate Page Views

Cause: GA4 code added in multiple locations (Site Header + Template + Module)

Fix:

  1. Search all templates for GA4 code
  2. Check Site Header HTML and Site Footer HTML
  3. Check custom modules
  4. Remove all but one instance

HubL Variables Not Working

Cause: HubL syntax errors or incorrect variable names

Debug:

{# Test HubL output #}
{{ contact.email }}
{{ contact.lifecycle_stage }}
{{ content.type }}

Common issues:

  • Contact variables only work for identified visitors
  • Blog variables only work on blog pages
  • Some variables require specific HubSpot subscriptions

Next Steps

For general GA4 concepts, see Google Analytics 4 Guide.

// SYS.FOOTER