ExpressionEngine (EE) is a PHP-based CMS that uses a proprietary template tag language with channel-based content modeling. Analytics integration uses EE's template system (template groups, snippets, global variables) or add-ons from the ExpressionEngine Store.
Integration Architecture
ExpressionEngine provides four integration paths:
- Templates -- EE's template groups contain template files (similar to views). Edit your site's layout template to add scripts to
<head>and<body>. Navigate to Developer > Templates. - Snippets -- Reusable template partials at Developer > Templates > Template Partials. Create a
tracking_headsnippet and include it with{snippet:tracking_head}in any template. - Global Variables -- Simple key-value pairs at Developer > Templates > Global Variables. Store a GTM container ID and reference it in templates with
{gv_gtm_id}. - Add-ons -- Install from the ExpressionEngine Store or via
php eecli.php addons:install. Add-ons can inject scripts via extension hooks.
Available Integrations
Analytics Platforms
- Layout template injection (direct gtag.js)
- GTM-based GA4 via template snippet (recommended)
Tag Management
- Layout template head/body injection
- Snippet-based GTM for multi-template sites
Marketing Pixels
- Via GTM container (recommended)
- Template head injection
Template Integration with Data Layer
Edit your primary layout template (typically in a _layouts or site template group). EE templates use the {exp:} tag syntax:
{!-- Layout template: _layouts/.group/index --}
<!DOCTYPE html>
<html lang="{site_language}">
<head>
<!-- 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-XXXX');</script>
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'siteLabel': '{site_label}',
'templateGroup': '{template_group}',
'templateName': '{template_name}',
'pageTitle': '{title}',
'entryId': '{entry_id}',
'channelName': '{channel_short_name}',
'memberGroup': '{logged_in_group_title}'
});
</script>
{layout:contents name="head"}
</head>
<body>
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
{layout:contents}
</body>
</html>
Channel Entry Data Layer
For pages displaying channel entries, use the {exp:channel:entries} tag to pass entry-specific data:
{exp:channel:entries limit="1" require_entry="yes"}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'entryId': '{entry_id}',
'entryTitle': '{title}',
'channelName': '{channel_short_name}',
'authorName': '{author}',
'entryDate': '{entry_date format="%Y-%m-%d"}',
'categories': '{categories backspace="1"}{category_name},{/categories}',
'status': '{status}'
});
</script>
{/exp:channel:entries}
Platform Limitations
Tag parsing conflicts. EE's template parser processes all { ... } pairs as potential tags. JavaScript object literals and template strings can trigger parse errors. Wrap JavaScript in {exp:comment} or use EE's {encode} tag for complex strings. Alternatively, load JavaScript from external files rather than inline.
No admin script injection UI. EE does not provide a "Custom Scripts" field in the control panel settings. All tracking code must be added via templates or add-ons. Content editors cannot modify tracking without template access.
Add-on ecosystem is small. The ExpressionEngine Store has a limited selection of analytics add-ons compared to WordPress or Drupal. Most GA4 and GTM implementations are done via manual template editing.
Multi-site tracking. EE's MSM (Multi-Site Manager) allows multiple sites from one installation. Each site can have different template groups, so tracking code must be added to each site's layout template independently. Use global variables ({gv_gtm_id}) to store per-site GTM container IDs.
Template caching. EE caches template output. Ensure dynamic data layer variables (member group, entry-specific data) are excluded from cached regions using {exp:channel:entries cache="no"} or EE's partial caching features.
Performance Considerations
- Template parsing overhead. EE's tag parser processes every template on each request (unless cached). Complex data layer templates with nested
{exp:channel:entries}and{categories}tags add parsing time. Keep data layer logic minimal in templates. - Add-on script loading. EE add-ons often inject their own CSS and JavaScript. Audit loaded scripts at Developer > Add-Ons to identify redundant analytics add-ons that could be consolidated through GTM.
- Database queries. Each
{exp:channel:entries}call executes SQL queries. The data layer template adds one additional query per page load. This is negligible on most hosting but can matter on high-traffic sites with complex channel relationships.
Recommended Integration Priority
- Add GTM to layout template -- Single container, applies to all template groups
- Create channel-aware data layer -- Use
{exp:channel:entries}for entry metadata in data layer - Store GTM ID in global variable -- Makes container ID changes admin-accessible
- Configure GA4 via GTM -- Map EE channels and categories to GA4 content groups
- Add Meta Pixel via GTM -- Standard content engagement tracking
Next Steps
For general integration concepts, see the integrations overview.