Expressionengine Analytics Integrations: Setup Guide | OpsBlu Docs

Expressionengine Analytics Integrations: Setup Guide

Integrate GA4, GTM, and Meta Pixel with ExpressionEngine using template groups, snippets, global variables, and add-ons.

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:

  1. 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.
  2. Snippets -- Reusable template partials at Developer > Templates > Template Partials. Create a tracking_head snippet and include it with {snippet:tracking_head} in any template.
  3. 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}.
  4. 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

Google Analytics 4

  • Layout template injection (direct gtag.js)
  • GTM-based GA4 via template snippet (recommended)

Tag Management

Google Tag Manager

  • Layout template head/body injection
  • Snippet-based GTM for multi-template sites

Marketing Pixels

Meta Pixel

  • 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.
  1. Add GTM to layout template -- Single container, applies to all template groups
  2. Create channel-aware data layer -- Use {exp:channel:entries} for entry metadata in data layer
  3. Store GTM ID in global variable -- Makes container ID changes admin-accessible
  4. Configure GA4 via GTM -- Map EE channels and categories to GA4 content groups
  5. Add Meta Pixel via GTM -- Standard content engagement tracking

Next Steps

For general integration concepts, see the integrations overview.