Install Google Tag Manager on MODX | OpsBlu Docs

Install Google Tag Manager on MODX

How to install GTM on MODX Revolution using templates, plugins, or chunks for centralized tag management.

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:

  1. GTM Account: Create account at tagmanager.google.com
  2. Container ID: Note your GTM container ID (format: GTM-XXXXXXX)
  3. MODX Access: Manager access to edit templates or install plugins
  4. Template Knowledge: Basic understanding of MODX templates

Install GTM directly in your MODX templates for maximum control.

Installation Steps

  1. Access Template Manager

    • Log into MODX Manager
    • Go to ElementsTemplates
    • Click on your base template (typically used across all pages)
  2. 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-XXXXXXX with your actual GTM container ID.

  3. 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-XXXXXXX with your container ID.

  4. 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 -->
    
  5. 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>
    
  6. Save and Clear Cache

    • Click Save
    • Go to ManageClear 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:

  1. Create Head Chunk

    • Go to ElementsChunksCreate New
    • Name: gtm_head
    • Content: GTM head code + data layer
  2. Create Body Chunk

    • Name: gtm_body
    • Content: GTM noscript code
  3. 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

  1. Create New Plugin

    • Go to ElementsPlugins
    • Click Create New Plugin
    • Name: GTM Injector
  2. 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;
    
  3. Set System Events

    • Click System Events tab in plugin editor
    • Check: OnWebPagePrerender
    • Save plugin
  4. Enable Plugin

    • Ensure plugin checkbox is enabled
    • Save
  5. Clear Cache and Test

    • ManageClear 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

  1. Access Package Manager

    • ExtrasInstaller
    • Click Download Extras
  2. Search for GTM Package

    • Search: "Google Tag Manager" or "GTM"
    • Popular packages:
      • TagManager
      • GoogleTagManager
  3. Install Package

    • Click Download next to desired package
    • Wait for installation to complete
  4. Configure Settings

    • Go to SystemSystem Settings
    • Search for GTM or TagManager settings
    • Enter your GTM Container ID
    • Configure additional options
    • Save
  5. Clear Cache

    • ManageClear 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

  1. Open GTMtagmanager.google.com
  2. Click Preview button (top right)
  3. Enter your MODX site URL
  4. Click Connect
  5. 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

  1. TagsNew
  2. Tag ConfigurationGoogle Analytics: GA4 Configuration
  3. Measurement ID: Enter your GA4 ID (G-XXXXXXXXXX)
  4. Configuration Settings:
    • Add MODX data layer variables
  5. Triggering: All Pages
  6. 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:

  1. SystemSystem SettingsCreate New Setting

    • Key: gtm_container_id
    • Value: GTM-XXXXXXX
    • Area: Analytics
  2. 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

For general GTM concepts, see Google Tag Manager Guide.