Magnoliacms Analytics Integrations: Setup Guide | OpsBlu Docs

Magnoliacms Analytics Integrations: Setup Guide

Integrate GA4, GTM, and Meta Pixel with Magnolia CMS using FreeMarker templates, the Light Module system, and Magnolia's headless API.

Magnolia CMS is a Java-based enterprise digital experience platform that supports both traditional server-rendered (FreeMarker templates) and headless (REST API) delivery. Analytics integration depends on which delivery model you use, and requires understanding Magnolia's dual-instance architecture (author vs public instances).

Integration Architecture

Magnolia provides four integration paths:

  1. FreeMarker Templates -- Edit page templates in your Light Module or Maven module. Templates at /templates/pages/ control page layout and can inject tracking scripts. Light Modules allow file-based development without Maven builds.
  2. Light Modules -- File-based modules in /<magnolia-home>/modules/. Create or edit templates, dialogs, and configurations by placing files in the correct directory structure. No compilation required.
  3. Headless/REST API -- Magnolia's Delivery API serves content as JSON. Frontend frameworks consume this API and handle analytics integration independently.
  4. Decoration -- Magnolia's decoration pattern extends existing templates without modifying them. Add tracking scripts by decorating the base page template.

Available Integrations

Analytics Platforms

Google Analytics 4

  • FreeMarker page template injection
  • GTM via Light Module (recommended)
  • Headless: frontend framework integration

Tag Management

Google Tag Manager

  • FreeMarker template head/body injection
  • Light Module-based configuration
  • Headless: frontend app shell

Marketing Pixels

Meta Pixel

  • Via GTM container (recommended)
  • FreeMarker template injection

FreeMarker Template Integration

Add GTM to your page template's FreeMarker file in a Light Module:

[#-- modules/yourmodule/templates/pages/base.ftl --]
<!DOCTYPE html>
<html lang="${cmsfn.language()!"en"}">
<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>

    [#assign content = cmsfn.contentByPath(state.handle)!]
    <script>
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
        'pageTemplate': '${state.handle!"unknown"}',
        'pageTitle': '${content.title!""|js_string}',
        'nodeType': '${content["jcr:primaryType"]!"mgnl:page"}',
        'workspace': '${cmsfn.workspace()!"website"}',
        'language': '${cmsfn.language()!"en"}',
        'depth': '${cmsfn.ancestors(content)?size}'
    });
    </script>

    [@cms.page /]
</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>

    [@cms.area name="main" /]
</body>
</html>

Light Module Configuration

Create a Light Module directory structure for analytics configuration:

modules/analytics/
├── templates/
│   └── components/
│       └── gtm-container.ftl
├── dialogs/
│   └── components/
│       └── gtm-container.yaml
└── decorations/
    └── pages/
        └── base.yaml

The dialog YAML allows editors to configure the GTM container ID via the Magnolia admin:

# modules/analytics/dialogs/components/gtm-container.yaml
form:
  tabs:
    - name: tabMain
      fields:
        - name: gtmId
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          label: GTM Container ID
          description: "Enter your GTM container ID (e.g., GTM-XXXX)"

Platform Limitations

Author vs Public instance. Magnolia runs two instances: the author instance (for content editing) and the public instance (for live content). Tracking scripts should only fire on the public instance. Use cmsfn.isEditMode() to conditionally exclude tracking during authoring:

[#if !cmsfn.isEditMode()]
  <!-- GTM code here -->
[/#if]

JCR repository caching. Magnolia uses a JCR content repository with caching layers. Data layer values rendered in FreeMarker templates are cached along with the page HTML. User-specific data must be populated client-side.

Personalization overlap. Magnolia's built-in Personalization module tracks visitor segments and behavior. Running both Magnolia Personalization and GA4 creates parallel data collection. Coordinate segment definitions between the two systems.

Headless complexity. When using Magnolia as a headless CMS (Delivery API), the frontend framework handles all analytics. The FreeMarker template integration described above does not apply. You must implement tracking in your React/Next.js/Vue frontend separately.

Maven module vs Light Module. Complex analytics integrations (server-side event hooks, custom servlets for Measurement Protocol) require Maven modules compiled into the Magnolia WAR. Light Modules are file-based and limited to templates, dialogs, and configuration.

Performance Considerations

  • JCR query performance. Accessing content properties in FreeMarker (cmsfn.contentByPath()) triggers JCR repository queries. On pages with many components, each component's data layer contribution adds a query. Pre-compute data layer values at the page level rather than per-component.
  • Public instance caching. Magnolia's page cache on the public instance serves pre-rendered HTML. Tracking scripts in cached pages load identically for all users, which is correct behavior. Ensure dynamic data layer values use client-side population.
  • Multi-site. Magnolia supports multi-site configurations. Each site can have different templates and configurations. Use site-specific GTM container IDs via dialog-configurable components.
  1. Add GTM to base page template -- Conditional on !cmsfn.isEditMode() to exclude author instance
  2. Build content-aware data layer -- Map Magnolia content types, workspace hierarchy, and language to data layer
  3. Configure GA4 via GTM -- Content groups from Magnolia page templates, custom dimensions from JCR properties
  4. Add Meta Pixel via GTM -- Standard engagement tracking

Next Steps

For general integration concepts, see the integrations overview.