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
Method 1: Using a GTM Module (Recommended)
Option A: Free GTM Modules
Popular Free Modules:
PrestaShop Official GTM Module (if available)
- Source: PrestaShop Addons
- Features: Basic GTM container integration
- Best for: Standard implementations
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
- Navigate to Modules > Module Manager
- Click Upload a Module
- Select downloaded module ZIP file
- 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:
Presta Module's GTM Enhanced
- Price: ~$79-149
- Features: Complete data layer, ecommerce tracking, custom events
- Support: Includes updates and support
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:
- Create Workspace: "PrestaShop Setup"
- Create Variables: See Data Layer documentation
- Create Tags: Start with GA4 Configuration tag
- Create Triggers: Page View, DOM Ready, etc.
- Test: Use Preview mode
- 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)
Consent Mode Integration
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
- In GTM, click Preview button
- Enter your PrestaShop store URL
- Click Connect
- 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
- Browse homepage → Check page view tags
- View product → Check product data in data layer
- Add to cart → Check cart event fires
- Checkout → Check checkout events
- 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:
- Install from Chrome Web Store
- Navigate to your PrestaShop store
- Click Tag Assistant icon
- Click Enable and refresh page
- 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
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:
- PrestaShop Data Layer - Implement comprehensive data layer
- GA4 via GTM - Set up GA4 through GTM
- Meta Pixel via GTM - Add Facebook tracking
For issues:
- Events Not Firing - Debug tracking problems