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+:
Access Tracking Codes
- Log in to Dashboard
- Go to System & Settings → SEO & Statistics → Tracking Codes
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-XXXXXXXXXXwith your GA4 Measurement ID.Save Settings
- Click Save
- Code will be added to all public pages
Clear Cache
- Go to Dashboard → System & Settings → Optimization → Clear 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:
Install Add-on from Marketplace
- Go to Dashboard → Extend Concrete CMS
- Search for "Header Extra HTML" or similar
- Install and activate
Add to Header
- Go to Dashboard → System & Settings → Basics → Header 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
Locate Theme Files
Your theme files are typically in:
/application/themes/[your-theme-name]/Or for package themes:
/packages/[package-name]/themes/[theme-name]/Edit Page Template Header
Open your theme's main layout file (often
view.phpordefault.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-XXXXXXXXXXwith your GA4 Measurement ID.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 } ?>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');
}
?>
Method 3: Google Tag Manager (Recommended)
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
Install GTM on Concrete CMS
See Install Google Tag Manager for full GTM installation guide.
Create GA4 Tag in GTM
Once GTM is installed:
a. In GTM, go to Tags → New
b. Click Tag Configuration → Google 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"
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.
Publish Container
- Click Submit in GTM
- Add version name and description
- Click Publish
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 → Reports → Realtime
- 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 Admin → DebugView
- View events in real-time with full parameters
3. Test Across Page Types
Test different Concrete CMS page types:
- Homepage → check page_view event
- Blog posts → verify content tracking
- Forms → check form submission events (if implemented)
- 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:
- Check Header/Footer tracking codes
- Check theme template files
- Check for marketplace tracking add-ons
- 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
- Configure GA4 Events - Track custom Concrete CMS events
- Install GTM - For easier tag management
- Troubleshoot Events - Debug tracking issues
For general GA4 concepts, see Google Analytics 4 Guide.