Google Tag Manager Setup on PrestaShop | Blue Frog Docs

Google Tag Manager Setup on PrestaShop

Install and configure Google Tag Manager on PrestaShop using modules or manual integration with PrestaShop's hook system.

Google Tag Manager Setup on PrestaShop

Implement Google Tag Manager (GTM) on your PrestaShop store to centralize tracking code management and enable flexible tag deployment without modifying templates.

Why Use GTM with PrestaShop?

Benefits for PrestaShop Stores

1. Centralized Tag Management

  • Deploy and update tracking tags without theme modifications
  • No need to edit Smarty templates for each tag change
  • Manage multiple tracking tools from one interface
  • Ideal for multi-store setups with different tracking needs

2. PrestaShop-Specific Advantages

  • Preserve tags during theme updates
  • No module conflicts with tracking scripts
  • Easy testing with Preview mode
  • Version control for tag configurations

3. Marketing Team Empowerment

  • Non-developers can add/modify tags
  • Faster campaign deployment
  • A/B testing without developer involvement
  • Real-time tag updates

4. Performance Benefits

  • Asynchronous tag loading
  • Tag firing optimization
  • Reduce direct template modifications
  • Better control over third-party scripts

Prerequisites

Before starting:

  • PrestaShop Version: 1.7.x or 8.x recommended
  • GTM Account: Create free account at tagmanager.google.com
  • GTM Container: Create container for your PrestaShop store
  • Container ID: Format GTM-XXXXXXX
  • Access Rights: PrestaShop Back Office module installation permissions
  • Development Environment: Test in staging before production

Option A: Free GTM Modules

Popular Free Modules:

  1. PrestaShop Official GTM Module (if available)

    • Source: PrestaShop Addons
    • Features: Basic GTM container integration
    • Best for: Standard implementations
  2. Community GTM Modules

    • Source: GitHub, forums
    • Features: Vary by developer
    • Best for: Developers comfortable customizing

Installation Steps

Step 1: Download Module

# If downloading from GitHub
cd /path/to/prestashop/modules/
git clone https://github.com/[developer]/prestashop-gtm.git gtm_module
cd gtm_module
composer install  # If module uses Composer

Step 2: Install via Back Office

  1. Navigate to Modules > Module Manager
  2. Click Upload a Module
  3. Select downloaded module ZIP file
  4. Click Configure after installation

Step 3: Configure Module

Configuration Fields:
- GTM Container ID: GTM-XXXXXXX
- Enable GTM: Yes
- Data Layer Name: dataLayer (default)
- Environment (optional): For GTM environments
- Debug Mode: Enable during setup

Step 4: Verify Installation

// Check in browser console
console.log(window.dataLayer);
// Should show array with GTM data

// Check GTM container loaded
console.log(window.google_tag_manager);
// Should show GTM object

Option B: Premium GTM Modules with Enhanced Features

Premium Module Features:

  • Enhanced Ecommerce Data Layer: Automatic product, cart, transaction tracking
  • Multi-Store Support: Different containers per store
  • Custom Event Builder: UI to create custom data layer events
  • Server-Side Tracking: Advanced implementation options
  • Priority Support: Developer assistance

Popular Premium Options:

  1. Presta Module's GTM Enhanced

    • Price: ~$79-149
    • Features: Complete data layer, ecommerce tracking, custom events
    • Support: Includes updates and support
  2. eBusiness Guru GTM Pro

    • Price: ~$99
    • Features: Advanced data layer, consent management integration
    • Support: Documentation and tickets

Evaluation Checklist:

  • PrestaShop version compatibility (1.6.x, 1.7.x, 8.x)
  • Data layer implementation quality
  • Multi-store capability
  • Update frequency and support responsiveness
  • User reviews and ratings
  • Refund policy

Method 2: Manual GTM Implementation

For complete control over GTM integration.

Step 1: Create Custom GTM Module

Module Structure:

modules/customgtm/
├── customgtm.php
├── config.xml
├── logo.png
└── views/
    └── templates/
        └── hook/
            ├── gtm-head.tpl
            └── gtm-body.tpl

Main Module File:

<?php
// modules/customgtm/customgtm.php

if (!defined('_PS_VERSION_')) {
    exit;
}

class CustomGTM extends Module
{
    public function __construct()
    {
        $this->name = 'customgtm';
        $this->tab = 'analytics_stats';
        $this->version = '1.0.0';
        $this->author = 'Your Name';
        $this->need_instance = 0;

        $this->bootstrap = true;
        parent::__construct();

        $this->displayName = $this->l('Custom Google Tag Manager');
        $this->description = $this->l('Integrate Google Tag Manager with PrestaShop');
        $this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
    }

    public function install()
    {
        Configuration::updateValue('CUSTOMGTM_CONTAINER_ID', '');
        Configuration::updateValue('CUSTOMGTM_ENABLED', 0);
        Configuration::updateValue('CUSTOMGTM_DATALAYER_NAME', 'dataLayer');

        return parent::install()
            && $this->registerHook('displayHeader')
            && $this->registerHook('displayFooter');
    }

    public function uninstall()
    {
        Configuration::deleteByName('CUSTOMGTM_CONTAINER_ID');
        Configuration::deleteByName('CUSTOMGTM_ENABLED');
        Configuration::deleteByName('CUSTOMGTM_DATALAYER_NAME');

        return parent::uninstall();
    }

    public function getContent()
    {
        $output = '';

        if (Tools::isSubmit('submitCustomGTM')) {
            $container_id = Tools::getValue('CUSTOMGTM_CONTAINER_ID');

            // Validate GTM container ID format
            if (!preg_match('/^GTM-[A-Z0-9]+$/', $container_id)) {
                $output .= $this->displayError($this->l('Invalid GTM Container ID format. Should be GTM-XXXXXXX'));
            } else {
                Configuration::updateValue('CUSTOMGTM_CONTAINER_ID', $container_id);
                Configuration::updateValue('CUSTOMGTM_ENABLED', Tools::getValue('CUSTOMGTM_ENABLED'));
                Configuration::updateValue('CUSTOMGTM_DATALAYER_NAME', Tools::getValue('CUSTOMGTM_DATALAYER_NAME'));
                $output .= $this->displayConfirmation($this->l('Settings updated successfully'));
            }
        }

        return $output . $this->renderForm();
    }

    protected function renderForm()
    {
        $fields_form = array(
            'form' => array(
                'legend' => array(
                    'title' => $this->l('GTM Settings'),
                    'icon' => 'icon-cogs'
                ),
                'input' => array(
                    array(
                        'type' => 'switch',
                        'label' => $this->l('Enable GTM'),
                        'name' => 'CUSTOMGTM_ENABLED',
                        'is_bool' => true,
                        'values' => array(
                            array('id' => 'active_on', 'value' => 1, 'label' => $this->l('Yes')),
                            array('id' => 'active_off', 'value' => 0, 'label' => $this->l('No'))
                        )
                    ),
                    array(
                        'type' => 'text',
                        'label' => $this->l('GTM Container ID'),
                        'name' => 'CUSTOMGTM_CONTAINER_ID',
                        'required' => true,
                        'desc' => $this->l('Your GTM Container ID (format: GTM-XXXXXXX)'),
                        'placeholder' => 'GTM-XXXXXXX'
                    ),
                    array(
                        'type' => 'text',
                        'label' => $this->l('Data Layer Name'),
                        'name' => 'CUSTOMGTM_DATALAYER_NAME',
                        'desc' => $this->l('Default is "dataLayer". Only change if using custom name.'),
                        'placeholder' => 'dataLayer'
                    )
                ),
                'submit' => array(
                    'title' => $this->l('Save'),
                    'class' => 'btn btn-default pull-right'
                )
            )
        );

        $helper = new HelperForm();
        $helper->module = $this;
        $helper->name_controller = $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
        $helper->submit_action = 'submitCustomGTM';
        $helper->default_form_language = (int)Configuration::get('PS_LANG_DEFAULT');

        $helper->fields_value['CUSTOMGTM_ENABLED'] = Configuration::get('CUSTOMGTM_ENABLED');
        $helper->fields_value['CUSTOMGTM_CONTAINER_ID'] = Configuration::get('CUSTOMGTM_CONTAINER_ID');
        $helper->fields_value['CUSTOMGTM_DATALAYER_NAME'] = Configuration::get('CUSTOMGTM_DATALAYER_NAME') ?: 'dataLayer';

        return $helper->generateForm(array($fields_form));
    }

    public function hookDisplayHeader($params)
    {
        if (!Configuration::get('CUSTOMGTM_ENABLED')) {
            return '';
        }

        $container_id = Configuration::get('CUSTOMGTM_CONTAINER_ID');

        if (empty($container_id)) {
            return '';
        }

        $this->context->smarty->assign(array(
            'gtm_container_id' => $container_id,
            'gtm_datalayer_name' => Configuration::get('CUSTOMGTM_DATALAYER_NAME') ?: 'dataLayer'
        ));

        return $this->display(__FILE__, 'views/templates/hook/gtm-head.tpl');
    }

    public function hookDisplayFooter($params)
    {
        if (!Configuration::get('CUSTOMGTM_ENABLED')) {
            return '';
        }

        $container_id = Configuration::get('CUSTOMGTM_CONTAINER_ID');

        if (empty($container_id)) {
            return '';
        }

        $this->context->smarty->assign(array(
            'gtm_container_id' => $container_id
        ));

        return $this->display(__FILE__, 'views/templates/hook/gtm-body.tpl');
    }
}

Step 2: Create GTM Templates

Head Template (loads in <head>):

{* modules/customgtm/views/templates/hook/gtm-head.tpl *}
<!-- 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','{$gtm_datalayer_name|escape:'javascript':'UTF-8'}','{$gtm_container_id|escape:'javascript':'UTF-8'}');
</script>
<!-- End Google Tag Manager -->

Body Template (loads in <body>):

{* modules/customgtm/views/templates/hook/gtm-body.tpl *}
<!-- Google Tag Manager (noscript) -->
<noscript>
  <iframe src="https://www.googletagmanager.com/ns.html?id={$gtm_container_id|escape:'html':'UTF-8'}"
          height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->

Step 3: Handle Multi-Store Setup

Different Containers Per Store:

// In hookDisplayHeader
public function hookDisplayHeader($params)
{
    if (!Configuration::get('CUSTOMGTM_ENABLED')) {
        return '';
    }

    $shop_id = (int)$this->context->shop->id;

    // Map shop IDs to GTM containers
    $containers = array(
        1 => 'GTM-XXXXX1',  // Main store
        2 => 'GTM-XXXXX2',  // Second brand
        3 => 'GTM-XXXXX3'   // Regional store
    );

    $container_id = isset($containers[$shop_id]) ? $containers[$shop_id] : Configuration::get('CUSTOMGTM_CONTAINER_ID');

    if (empty($container_id)) {
        return '';
    }

    $this->context->smarty->assign(array(
        'gtm_container_id' => $container_id,
        'gtm_datalayer_name' => 'dataLayer'
    ));

    return $this->display(__FILE__, 'views/templates/hook/gtm-head.tpl');
}

Method 3: Direct Theme Integration

Only if you have full control over theme and updates.

Modify Theme Header Template

File: themes/[your-theme]/templates/_partials/head.tpl

Add before </head>:

{* Google Tag Manager *}
<!-- 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 -->

Modify Theme Body Template

File: themes/[your-theme]/templates/layout/layout.tpl

Add right after opening <body> tag:

<!-- 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) -->

Important: This method requires re-applying changes after theme updates.

GTM Container Configuration

Initial Container Setup

In Google Tag Manager:

  1. Create Workspace: "PrestaShop Setup"
  2. Create Variables: See Data Layer documentation
  3. Create Tags: Start with GA4 Configuration tag
  4. Create Triggers: Page View, DOM Ready, etc.
  5. Test: Use Preview mode
  6. Publish: Create version and publish

Basic Tag Setup (GA4 Example)

Tag Configuration:

Tag Type: Google Analytics: GA4 Configuration
Tag Name: GA4 - Configuration
Measurement ID: G-XXXXXXXXXX

Triggering: All Pages

Fields to Set:
- send_page_view: true
- debug_mode: false (true for testing)

PrestaShop requires GDPR compliance:

// Add to GTM Custom HTML tag - fires before GTM loads
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}

  // Default consent state
  gtag('consent', 'default', {
    'analytics_storage': 'denied',
    'ad_storage': 'denied',
    'wait_for_update': 500
  });

  // Update consent when user accepts
  document.addEventListener('DOMContentLoaded', function() {
    // Check PrestaShop cookie consent
    if (typeof prestashop !== 'undefined' && prestashop.gdprConsent) {
      if (prestashop.gdprConsent.analytics) {
        gtag('consent', 'update', {
          'analytics_storage': 'granted'
        });
      }
      if (prestashop.gdprConsent.marketing) {
        gtag('consent', 'update', {
          'ad_storage': 'granted'
        });
      }
    }
  });
</script>

Testing GTM Installation

Using GTM Preview Mode

Step 1: Enable Preview

  1. In GTM, click Preview button
  2. Enter your PrestaShop store URL
  3. Click Connect
  4. New tab opens with debugger

Step 2: Verify Installation

Check:

  • GTM container loads
  • Data layer exists and populates
  • Tags fire on appropriate triggers
  • Variables resolve correctly

Step 3: Test User Flow

  1. Browse homepage → Check page view tags
  2. View product → Check product data in data layer
  3. Add to cart → Check cart event fires
  4. Checkout → Check checkout events
  5. Complete test order → Check purchase event

Browser Console Verification

// Check GTM loaded
typeof google_tag_manager !== 'undefined'
// Returns: true

// Check data layer
window.dataLayer
// Returns: Array with data layer pushes

// Check specific data
window.dataLayer.filter(item => item.event === 'gtm.js')
// Returns: GTM initialization events

Using Tag Assistant

Google Tag Assistant Chrome Extension:

  1. Install from Chrome Web Store
  2. Navigate to your PrestaShop store
  3. Click Tag Assistant icon
  4. Click Enable and refresh page
  5. Review detected tags and issues

Multi-Store GTM Strategy

Approach 1: Separate Containers

Use when:

  • Stores are completely different brands
  • Different marketing teams manage each store
  • Different analytics properties needed

Configuration:

// Per-store container mapping in module
$shop_id = $this->context->shop->id;
$containers = array(
    1 => 'GTM-MAIN01',
    2 => 'GTM-BRAND2',
    3 => 'GTM-REGION3'
);

Approach 2: Single Container with Store Variable

Use when:

  • Stores share marketing team
  • Consolidated reporting needed
  • Same tracking requirements

Add store variable to data layer:

window.dataLayer = window.dataLayer || [];
dataLayer.push({
  'shopId': '{$shop.id}',
  'shopName': '{$shop.name}',
  'shopGroup': '{$shop.id_shop_group}'
});

Performance Optimization

Async Loading Best Practices

GTM loads asynchronously by default, but optimize further:

1. Defer Non-Critical Tags

  • Set tag firing priority
  • Use DOM Ready vs Page View triggers
  • Delay marketing tags until interaction

2. Minimize Data Layer Size

  • Only push necessary data
  • Avoid large objects in data layer
  • Clean up temporary variables

3. Cache GTM Container

  • GTM container is cached by browser
  • Ensure cache headers allow caching
  • Consider CDN for gtm.js

PrestaShop Cache Compatibility

Ensure GTM works with:

  • PrestaShop Smarty cache
  • Full page cache (Varnish)
  • Third-party cache modules

Test with cache enabled:

# Clear PrestaShop cache
rm -rf var/cache/*

# Regenerate cache
# Back Office > Advanced Parameters > Performance > Clear cache

Troubleshooting

GTM Not Loading

Check:

  • Container ID format is correct (GTM-XXXXXXX)
  • Module is enabled
  • PrestaShop cache is cleared
  • No JavaScript errors in console
  • Ad blockers disabled (for testing)

Debug:

// Check if GTM script exists in DOM
document.querySelector('script[src*="googletagmanager.com/gtm.js"]')

Data Layer Not Populating

Check:

  • Data layer initialized before GTM loads
  • Variable names match exactly
  • Data layer pushes occur before tag fires
  • No JavaScript errors preventing pushes

Debug:

// Monitor data layer changes
var originalPush = window.dataLayer.push;
window.dataLayer.push = function() {
  console.log('Data Layer Push:', arguments);
  return originalPush.apply(this, arguments);
};

Tags Not Firing

Check:

  • Triggers configured correctly
  • Preview mode shows trigger activation
  • Tag firing priority
  • Consent state allows tag firing

Next Steps

Now that GTM is installed:

For issues:

// SYS.FOOTER