Google Tag Manager (GTM) provides centralized management for all tracking tags on your MODX website. This guide covers installation methods specific to MODX Revolution.
Why Use GTM with MODX?
Benefits:
- No template editing for tag updates after initial setup
- Centralized management of all marketing tags
- Access to MODX data via custom data layer
- Better performance than multiple individual scripts
- Non-technical updates via GTM interface
- Version control for tag configurations
- Preview and debug before publishing
Best for:
- Sites with multiple tracking tools (GA4, Meta Pixel, etc.)
- Marketing teams that need to add/modify tags
- Sites requiring frequent tracking updates
- Complex event tracking implementations
Prerequisites
Before installing GTM on MODX:
- GTM Account: Create account at tagmanager.google.com
- Container ID: Note your GTM container ID (format:
GTM-XXXXXXX) - MODX Access: Manager access to edit templates or install plugins
- Template Knowledge: Basic understanding of MODX templates
Method 1: Template-Based Installation (Recommended)
Install GTM directly in your MODX templates for maximum control.
Installation Steps
Access Template Manager
- Log into MODX Manager
- Go to Elements → Templates
- Click on your base template (typically used across all pages)
Add GTM Code to Template Head
Find the opening
<head>tag and add immediately after:<!-- Google Tag Manager --> <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-XXXXXXX');</script> <!-- End Google Tag Manager -->Replace
GTM-XXXXXXXwith your actual GTM container ID.Add GTM Noscript to Template Body
Find the opening
<body>tag and add immediately after:<!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) -->Replace
GTM-XXXXXXXwith your container ID.Add MODX Data Layer (Optional but Recommended)
Before the GTM head code, add MODX resource data:
<!-- MODX Data Layer --> <script> window.dataLayer = window.dataLayer || []; dataLayer.push({ 'pageType': '[[*template:is=`1`:then=`home`:else=`content`]]', 'resourceId': '[[*id]]', 'pageTitle': '[[*pagetitle]]', 'template': '[[*template]]', 'parentId': '[[*parent]]', 'context': '[[!++context_key]]', 'published': '[[*published]]', 'userLoggedIn': [[!+modx.user.id:notempty=`true`:default=`false`]], [[!+modx.user.id:notempty=`'userId': '[[!+modx.user.id]]',`]] }); </script> <!-- End MODX Data Layer -->Complete Template Example
<!DOCTYPE html> <html lang="[[++cultureKey]]"> <head> <meta charset="[[++modx_charset]]"> <base href="[[!++site_url]]"> <title>[[*pagetitle]] - [[++site_name]]</title> <!-- MODX Data Layer --> <script> window.dataLayer = window.dataLayer || []; dataLayer.push({ 'pageType': '[[*template:is=`1`:then=`home`:else=`content`]]', 'resourceId': '[[*id]]', 'pageTitle': '[[*pagetitle]]', 'template': '[[*template]]', 'parentId': '[[*parent]]', 'context': '[[!++context_key]]' }); </script> <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-XXXXXXX');</script> <!-- End Google Tag Manager --> </head> <body> <!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXXX" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) --> [[*content]] </body> </html>Save and Clear Cache
- Click Save
- Go to Manage → Clear Cache
- Visit your site to verify GTM loads
Multiple Templates
If your site uses multiple templates:
Option A: Add to Each Template
- Copy GTM code to all templates
- Ensures GTM on all pages
Option B: Use Chunks (Recommended)
Create reusable chunks:
Create Head Chunk
- Go to Elements → Chunks → Create New
- Name:
gtm_head - Content: GTM head code + data layer
Create Body Chunk
- Name:
gtm_body - Content: GTM noscript code
- Name:
Use in Templates
<head> [[$gtm_head]] </head> <body> [[$gtm_body]] [[*content]] </body>
Benefits of chunks:
- Single location to update GTM container ID
- Easy to maintain across templates
- Can update all pages at once
Method 2: Plugin-Based Installation
Use MODX plugins to automatically inject GTM on all pages.
Custom Plugin Setup
Create New Plugin
- Go to Elements → Plugins
- Click Create New Plugin
- Name:
GTM Injector
Plugin Code
<?php /** * GTM Injector Plugin * Automatically adds Google Tag Manager to all pages * * System Events: OnWebPagePrerender */ $gtmId = 'GTM-XXXXXXX'; // Replace with your GTM Container ID // Build MODX data layer $dataLayer = [ 'pageType' => ($modx->resource->get('template') == 1) ? 'home' : 'content', 'resourceId' => $modx->resource->get('id'), 'pageTitle' => $modx->resource->get('pagetitle'), 'template' => $modx->resource->get('template'), 'parentId' => $modx->resource->get('parent'), 'context' => $modx->context->get('key'), 'published' => $modx->resource->get('published') ]; // Add user data if logged in if ($modx->user->isAuthenticated('web')) { $dataLayer['userLoggedIn'] = true; $dataLayer['userId'] = $modx->user->get('id'); } else { $dataLayer['userLoggedIn'] = false; } $dataLayerJson = json_encode($dataLayer, JSON_UNESCAPED_SLASHES); $gtmHeadCode = <<<HTML <!-- MODX Data Layer --> <script> window.dataLayer = window.dataLayer || []; dataLayer.push({$dataLayerJson}); </script> <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','{$gtmId}');</script> <!-- End Google Tag Manager --> HTML; $gtmBodyCode = <<<HTML <!-- Google Tag Manager (noscript) --> <noscript><iframe src="https://www.googletagmanager.com/ns.html?id={$gtmId}" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> <!-- End Google Tag Manager (noscript) --> HTML; // Inject GTM code $output = $modx->resource->_output; $output = str_replace('</head>', $gtmHeadCode . '</head>', $output); $output = preg_replace('/<body([^>]*)>/', '<body$1>' . $gtmBodyCode, $output, 1); $modx->resource->_output = $output;Set System Events
- Click System Events tab in plugin editor
- Check:
OnWebPagePrerender - Save plugin
Enable Plugin
- Ensure plugin checkbox is enabled
- Save
Clear Cache and Test
- Manage → Clear Cache
- Visit site
- Verify GTM loads in browser console
Plugin Benefits
Advantages:
- No template editing required
- Automatically applies to all pages
- Centralized GTM configuration
- Easy to enable/disable
Disadvantages:
- Slightly impacts page generation time
- Harder to debug than template code
- May conflict with other plugins
Method 3: Using MODX Extras
Install pre-built GTM packages from MODX Extras.
Installation via Package Manager
Access Package Manager
- Extras → Installer
- Click Download Extras
Search for GTM Package
- Search: "Google Tag Manager" or "GTM"
- Popular packages:
- TagManager
- GoogleTagManager
Install Package
- Click Download next to desired package
- Wait for installation to complete
Configure Settings
- Go to System → System Settings
- Search for GTM or TagManager settings
- Enter your GTM Container ID
- Configure additional options
- Save
Clear Cache
- Manage → Clear Cache
- Test on your site
Note: Availability and features of Extras vary. Check package documentation for specific configuration.
Multi-Context Setup
If using MODX contexts (e.g., web, mobile, api):
Different Containers per Context
<!-- In template or plugin -->
[[switch? &value=`[[!++context_key]]`
&case=`web=GTM-AAAAAAA`
&case=`mobile=GTM-BBBBBBB`
&default=`GTM-AAAAAAA`
]]
Or in plugin:
$gtmId = match($modx->context->get('key')) {
'web' => 'GTM-AAAAAAA',
'mobile' => 'GTM-BBBBBBB',
default => 'GTM-AAAAAAA'
};
Verification & Testing
1. Verify GTM Installation
Browser Console Check:
// Open Console (F12)
console.log(window.google_tag_manager);
// Should show GTM object with your container ID
View Page Source:
- Right-click → View Page Source
- Search for
GTM-XXXXXXX - Should appear in both
<head>and<body>
2. GTM Preview Mode
- Open GTM → tagmanager.google.com
- Click Preview button (top right)
- Enter your MODX site URL
- Click Connect
- Tag Assistant window opens showing:
- GTM container loaded
- Data layer values
- Tags firing
- Variables available
3. Verify MODX Data Layer
In browser console:
console.table(window.dataLayer);
Should show MODX resource data:
[{
pageType: "content",
resourceId: "5",
pageTitle: "About Us",
template: "2",
parentId: "0",
context: "web"
}]
4. Test Across Resources
Test GTM on:
- Homepage (resource ID 1)
- Content pages
- Different templates
- Forms
- Custom resources
Configure GTM Tags
Once GTM is installed, add your tracking tags:
GA4 Configuration Tag
- Tags → New
- Tag Configuration → Google Analytics: GA4 Configuration
- Measurement ID: Enter your GA4 ID (G-XXXXXXXXXX)
- Configuration Settings:
- Add MODX data layer variables
- Triggering: All Pages
- Save: Name "GA4 - Configuration"
Create MODX Variables in GTM
Resource ID Variable:
- Type: Data Layer Variable
- Data Layer Variable Name:
resourceId - Name:
DLV - Resource ID
Page Title:
- Type: Data Layer Variable
- Data Layer Variable Name:
pageTitle - Name:
DLV - Page Title
Template:
- Type: Data Layer Variable
- Data Layer Variable Name:
template - Name:
DLV - Template
See MODX Data Layer Structure for complete variable setup.
Troubleshooting
GTM Not Loading
Checklist:
- Container ID is correct (GTM-XXXXXXX)
- Code in both
<head>and<body> - MODX cache is cleared
- Template is saved
- Plugin is enabled (if using plugin)
Check browser console:
console.log(window.google_tag_manager);
// Should not be undefined
Data Layer Not Populating
Issue: Data layer is empty or missing MODX data.
Causes:
- Data layer code not before GTM code
- MODX tags not parsing (cached incorrectly)
- JavaScript errors blocking execution
Fix:
<!-- Data layer MUST come BEFORE GTM code -->
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({...});
</script>
<!-- Then GTM code -->
<script>(...GTM code...)</script>
MODX Placeholders Not Resolving
Issue: Placeholders appear as literal text in data layer.
Fix:
// Ensure proper syntax
[[*id]] // Resource field ✓
{*id} // Wrong ✗
// Use uncached tags if needed
[[!*pagetitle]] // Uncached
[[*pagetitle]] // Cached (usually fine)
GTM Preview Not Connecting
Checklist:
- Site is accessible (not localhost without special setup)
- No browser extensions blocking Tag Assistant
- GTM container is not published with errors
- Clear browser cache
Multiple GTM Containers
Issue: Multiple GTM snippets on same page.
Cause: Template + Plugin both adding GTM.
Fix: Choose ONE method:
- Remove from template if using plugin
- Disable plugin if using template
Best Practices
1. Use System Settings
Store GTM ID in MODX system settings:
System → System Settings → Create New Setting
- Key:
gtm_container_id - Value:
GTM-XXXXXXX - Area: Analytics
- Key:
Use in template/plugin:
[[++gtm_container_id]]
Benefits: Easy to update, no code editing
2. Implement Proper Data Layer
Always include MODX data before GTM:
- Resource ID
- Page title
- Template
- User status
3. Test Before Publishing
- Use GTM Preview mode
- Verify all variables capture data
- Test all triggers fire correctly
- Check Tag Assistant for errors
4. Document Your Setup
Keep track of:
- Installation method used
- Container IDs
- Data layer structure
- Custom variables created
Next Steps
- MODX Data Layer Structure - Build comprehensive data layer
- GA4 Setup via GTM - Add GA4 through GTM
- Meta Pixel Setup - Add Meta Pixel through GTM
For general GTM concepts, see Google Tag Manager Guide.