Install Google Analytics 4 on Concrete CMS | OpsBlu Docs

Install Google Analytics 4 on Concrete CMS

How to install GA4 on Concrete CMS (formerly Concrete5) using Header/Footer blocks, page templates, or Google Tag Manager.

There are three main methods to install GA4 on your Concrete CMS website, each with different capabilities and ease of implementation.

Method Comparison

Method Difficulty Flexibility Updates Required Recommended For
Header/Footer Block Easy Low Via Dashboard Quick setup, non-technical users
Page Template Medium Medium File editing Custom themes, specific page types
Google Tag Manager Medium High Via GTM interface Most sites (recommended)

Method 1: Header/Footer Block (Easiest)

The simplest method using Concrete CMS's built-in tracking code functionality or a marketplace add-on.

Option A: Built-in Tracking Codes

Concrete CMS v9+:

  1. Access Tracking Codes

    • Log in to Dashboard
    • Go to System & SettingsSEO & StatisticsTracking Codes
  2. Add GA4 Code

    Add the following to the "Tracking Code" 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', {
        'send_page_view': true
      });
    </script>
    

    Replace G-XXXXXXXXXX with your GA4 Measurement ID.

  3. Save Settings

    • Click Save
    • Code will be added to all public pages
  4. Clear Cache

    • Go to DashboardSystem & SettingsOptimizationClear Cache
    • Clear cache to ensure code appears

Option B: Header Extra HTML Block

If your Concrete CMS version doesn't have built-in tracking codes:

  1. Install Add-on from Marketplace

    • Go to DashboardExtend Concrete CMS
    • Search for "Header Extra HTML" or similar
    • Install and activate
  2. Add to Header

    • Go to DashboardSystem & SettingsBasicsHeader Extra HTML
    • Add the GA4 code (same as above)
    • Save

What Gets Tracked (Header/Footer Method)

All Sites:

  • Page views on all public pages
  • Basic user interactions
  • Standard GA4 automatic events

Not Tracked by Default:

  • Form submissions (requires custom implementation)
  • File downloads (requires custom implementation)
  • External link clicks (requires custom implementation)
  • E-commerce events (requires additional setup)

Limitations of Header/Footer Block

  • No easy way to add custom events without code
  • Cannot easily customize per page type
  • Limited control over when scripts load
  • May load on edit mode if not properly configured

Method 2: Page Template Implementation

Add GA4 directly to your theme templates for more control.

Setup Steps

  1. Locate Theme Files

    Your theme files are typically in:

    /application/themes/[your-theme-name]/
    

    Or for package themes:

    /packages/[package-name]/themes/[theme-name]/
    
  2. Edit Page Template Header

    Open your theme's main layout file (often view.php or default.php).

    Find the </head> closing tag and add GA4 code above it:

    <?php
    // Exclude tracking on edit mode and dashboard pages
    if (!$c->isEditMode() && !$this->controller->isControllerTaskInstanceOf('DashboardPageController')) {
        ?>
        <!-- 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,
            'page_title': '<?php echo addslashes($c->getCollectionName()); ?>',
            'page_path': '<?php echo $c->getCollectionPath(); ?>'
          });
        </script>
        <?php
    }
    ?>
    </head>
    

    Replace G-XXXXXXXXXX with your GA4 Measurement ID.

  3. Add User Properties (Optional)

    For logged-in user tracking:

    <?php
    if (!$c->isEditMode() && !$this->controller->isControllerTaskInstanceOf('DashboardPageController')) {
        $u = Core::make('Concrete\Core\User\User');
        $userID = '';
        $userType = 'guest';
    
        if ($u->isRegistered()) {
            $userID = $u->getUserID();
            $userType = 'registered';
        }
        ?>
        <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,
            'user_id': '<?php echo $userID; ?>',
            'user_type': '<?php echo $userType; ?>'
          });
        </script>
        <?php
    }
    ?>
    
  4. Clear Cache and Test

    • Dashboard → System & Settings → Optimization → Clear Cache
    • Visit your site in incognito mode
    • Check GA4 Realtime reports

Conditional Loading by Page Type

Track different page types differently:

<?php
if (!$c->isEditMode() && !$this->controller->isControllerTaskInstanceOf('DashboardPageController')) {
    $pageType = $c->getPageTypeHandle();
    ?>
    <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,
        'page_type': '<?php echo $pageType; ?>',
        'page_title': '<?php echo addslashes($c->getCollectionName()); ?>'
      });
    </script>
    <?php
}
?>

Using Concrete CMS Asset System

For better performance, use the asset system:

Create a file: /application/themes/[your-theme]/js/ga4-init.js

window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX', {
  'send_page_view': true
});

In your page template:

<?php
if (!$c->isEditMode() && !$this->controller->isControllerTaskInstanceOf('DashboardPageController')) {
    // Register GA4 base script
    $this->addHeaderItem('<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>');

    // Register initialization script
    $this->requireAsset('javascript', 'ga4-init');
}
?>

GTM provides the most flexibility and is recommended for most Concrete CMS sites.

Why Use GTM?

  • Easier to manage: Update tracking without editing theme files
  • Better organization: All tags in one place
  • Advanced features: Custom events, triggers, variables
  • Better performance: Single container load for multiple tags
  • Non-technical updates: Marketers can update without developers

Setup Steps

  1. Install GTM on Concrete CMS

    See Install Google Tag Manager for full GTM installation guide.

  2. Create GA4 Tag in GTM

    Once GTM is installed:

    a. In GTM, go to TagsNew

    b. Click Tag ConfigurationGoogle Analytics: GA4 Configuration

    c. Enter your Measurement ID (G-XXXXXXXXXX)

    d. Configuration Settings (optional):

    • Add user_id for logged-in users
    • Add custom parameters for page type, etc.

    e. Triggering: Select All Pages

    f. Save and name it "GA4 - Configuration"

  3. Configure Custom Parameters (Optional)

    In the GA4 Configuration tag, add Fields to Set:

    Using Concrete CMS Data Layer Variables:

    page_type = {{CMS - Page Type}}
    user_type = {{CMS - User Type}}
    

    You'll need to create these variables in GTM using Concrete CMS data layer.

  4. Publish Container

    • Click Submit in GTM
    • Add version name and description
    • Click Publish
  5. Test

    • Use GTM Preview mode to verify tags fire
    • Check GA4 Realtime reports
    • Verify data layer variables populate correctly

GTM + Concrete CMS Data Layer

See:

Verification & Testing

1. Check GA4 Realtime Reports

  • Open GA4 → ReportsRealtime
  • Navigate your site
  • Verify events appear within 30 seconds

2. Use GA4 DebugView

Enable debug mode to see detailed event data:

In GTM:

  • Use Preview mode
  • Events automatically appear in DebugView

Manual Implementation:

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

In GA4:

  • Go to AdminDebugView
  • View events in real-time with full parameters

3. Test Across Page Types

Test different Concrete CMS page types:

  1. Homepage → check page_view event
  2. Blog posts → verify content tracking
  3. Forms → check form submission events (if implemented)
  4. Landing pages → verify campaign parameters

4. Check for Common Issues

  • Events in edit mode: Verify tracking excluded during editing
  • Dashboard events: Ensure admin pages excluded
  • Cache issues: Clear Concrete CMS cache after changes
  • Duplicate events: Check for multiple implementations

Excluding Admin and Edit Pages

Always exclude these pages from tracking:

<?php
// Check if NOT in edit mode AND NOT in dashboard
if (!$c->isEditMode() && !$this->controller->isControllerTaskInstanceOf('DashboardPageController')) {
    // Add tracking code here
}
?>

Additional exclusions:

<?php
$app = \Concrete\Core\Support\Facade\Application::getFacadeApplication();
$c = \Page::getCurrentPage();
$u = $app->make(\Concrete\Core\User\User::class);

// Exclude edit mode, dashboard, and logged-in admins (optional)
if (!$c->isEditMode() &&
    !$this->controller->isControllerTaskInstanceOf('DashboardPageController') &&
    !$u->isSuperUser()) {
    // Add tracking code
}
?>

Troubleshooting

Events Not Firing

See Events Not Firing Troubleshooting for detailed debugging steps.

Quick checks:

  • Verify Measurement ID is correct (starts with G-)
  • Check browser console for JavaScript errors
  • Ensure ad blockers are disabled for testing
  • Clear Concrete CMS cache after changes
  • Verify code not in edit mode

Tracking in Edit Mode

Problem: GA4 tracking when editing pages.

Solution: Always add edit mode check:

if (!$c->isEditMode()) {
    // Tracking code
}

Cache Issues

Problem: Changes not appearing after updating code.

Solution: Clear cache:

  • Dashboard → System & Settings → Optimization → Clear Cache
  • Or via CLI: concrete/bin/concrete5 c5:clear-cache

Duplicate Events

Cause: Multiple implementations (Header block + Template code).

Fix:

  1. Check Header/Footer tracking codes
  2. Check theme template files
  3. Check for marketplace tracking add-ons
  4. Remove all but one implementation

Privacy Considerations

GDPR/CCPA Compliance

Wait for user consent before loading GA4:

<?php if (!$c->isEditMode()) { ?>
<script>
// Check for consent cookie
if (document.cookie.indexOf('analytics_consent=true') !== -1) {
  // Load GA4
  (function() {
    var script = document.createElement('script');
    script.async = true;
    script.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX';
    document.head.appendChild(script);

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

IP Anonymization

GA4 anonymizes IPs by default, but you can explicitly set:

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

Next Steps

For general GA4 concepts, see Google Analytics 4 Guide.