Silverstripe Analytics Integrations: Setup Guide | OpsBlu Docs

Silverstripe Analytics Integrations: Setup Guide

Available integrations for SilverStripe CMS sites including analytics platforms, tag managers, and marketing pixels.

SilverStripe is a flexible, open-source CMS and framework built on PHP. It's popular in Australia, New Zealand, and government sectors, offering enterprise-grade content management with developer-friendly architecture.

Available Integrations

Analytics Platforms

Google Analytics 4

  • SilverStripe module installation
  • DataObject tracking
  • CMS user exclusion
  • Elemental block analytics

Tag Management

Google Tag Manager

  • GTM module configuration
  • Data layer for SilverStripe pages
  • Content block tracking
  • Form submission events

Marketing Pixels

Meta Pixel

  • Pixel implementation
  • Lead form tracking
  • Event configuration
  • Privacy compliance

SilverStripe-Specific Integration Considerations

ORM-Based Architecture

SilverStripe uses an object-relational mapping system:

  • DataObjects: Content stored as database records
  • Page Types: Custom page classes with fields
  • Elemental Blocks: Modular content components
  • Versioned Content: Draft/published workflow

Template Integration

Implement tracking via SilverStripe templates:

<%-- In templates/Includes/Analytics.ss --%>

<% if $SiteConfig.GoogleAnalyticsID %>
<script async src="https://www.googletagmanager.com/gtag/js?id={$SiteConfig.GoogleAnalyticsID}"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', '{$SiteConfig.GoogleAnalyticsID}', {
    page_id: '{$ID}',
    page_title: '{$Title.JS}',
    page_type: '{$ClassName}',
    <% if $Author %>
    author: '{$Author.Title.JS}',
    <% end_if %>
    <% if $Categories.exists %>
    categories: '{$Categories.Column("Title").implode(",")}'
    <% end_if %>
  });
</script>
<% end_if %>

DataExtension for Analytics

Extend pages with analytics data:

<?php
// app/src/Extensions/AnalyticsPageExtension.php

namespace App\Extensions;

use SilverStripe\ORM\DataExtension;
use SilverStripe\View\Requirements;

class AnalyticsPageExtension extends DataExtension
{
    public function getAnalyticsData(): array
    {
        return [
            'page_id' => $this->owner->ID,
            'page_title' => $this->owner->Title,
            'page_type' => $this->owner->ClassName,
            'page_url' => $this->owner->AbsoluteLink(),
            'last_edited' => $this->owner->LastEdited,
            'created' => $this->owner->Created,
        ];
    }

    public function contentControllerInit($controller)
    {
        if (!$this->owner->config()->get('exclude_from_analytics')) {
            Requirements::customScript($this->getTrackingScript());
        }
    }

    private function getTrackingScript(): string
    {
        $data = json_encode($this->getAnalyticsData());
        return "window.pageAnalytics = {$data};";
    }
}

Elemental Block Tracking

Track SilverStripe Elemental blocks:

<?php
// app/src/Extensions/ElementalAnalyticsExtension.php

namespace App\Extensions;

use SilverStripe\ORM\DataExtension;

class ElementalAnalyticsExtension extends DataExtension
{
    public function getBlockAnalyticsData(): array
    {
        return [
            'block_id' => $this->owner->ID,
            'block_type' => $this->owner->ClassName,
            'block_title' => $this->owner->Title,
            'block_position' => $this->owner->Sort,
            'parent_page_id' => $this->owner->Parent()?->ID,
        ];
    }
}
<%-- In element template --%>
<section
  class="element-{$ClassName.ShortName}"
  data-block-id="{$ID}"
  data-block-type="{$ClassName.ShortName}"
  data-block-position="{$Sort}"
>
  $ElementContent
</section>

<script>
// Track block visibility
document.querySelectorAll('[data-block-id]').forEach(block => {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        gtag('event', 'block_view', {
          block_id: entry.target.dataset.blockId,
          block_type: entry.target.dataset.blockType,
          block_position: entry.target.dataset.blockPosition
        });
        observer.unobserve(entry.target);
      }
    });
  }, { threshold: 0.5 });
  observer.observe(block);
});
</script>

Form Tracking

Track SilverStripe UserForms submissions:

<?php
// app/src/Extensions/UserFormAnalyticsExtension.php

namespace App\Extensions;

use SilverStripe\ORM\DataExtension;

class UserFormAnalyticsExtension extends DataExtension
{
    public function updateAfterProcess($data, $form, $submission)
    {
        // Add tracking data to response
        $trackingData = [
            'form_id' => $this->owner->ID,
            'form_name' => $this->owner->Title,
            'submission_id' => $submission->ID,
        ];

        // This data can be picked up by client-side JavaScript
        Requirements::customScript(
            "window.formSubmission = " . json_encode($trackingData) . ";"
        );
    }
}

CMS User Exclusion

Exclude logged-in CMS users from analytics:

<?php
// In AnalyticsPageExtension.php

use SilverStripe\Security\Security;

public function shouldTrack(): bool
{
    $member = Security::getCurrentUser();

    if ($member && $member->inGroup('administrators')) {
        return false;
    }

    return true;
}
<%-- In template --%>
<% if $shouldTrack %>
  <% include Analytics %>
<% end_if %>

Integration Best Practices

1. Use Page IDs for Tracking

SilverStripe pages have stable database IDs:

gtag('event', 'content_view', {
  content_id: '{$ID}', // Stable database ID
  content_url_segment: '{$URLSegment}', // May change
  content_class: '{$ClassName}'
});

2. Track Page Hierarchy

Leverage SilverStripe's page tree:

<%-- Get breadcrumb for tracking --%>
<% cached 'analytics-breadcrumb', $ID, $LastEdited %>
<script>
gtag('event', 'page_view', {
  page_id: '{$ID}',
  breadcrumb: '<% loop $Breadcrumbs %>{$Title}<% if not $Last %> > <% end_if %><% end_loop %>',
  parent_id: '{$ParentID}',
  level: {$Level}
});
</script>
<% end_cached %>

3. Handle Versioned Content

Track draft vs. published content:

public function getVersionInfo(): array
{
    return [
        'is_published' => $this->owner->isPublished(),
        'is_modified' => $this->owner->stagesDiffer(),
        'version' => $this->owner->Version,
    ];
}

4. Track Subsites

For SilverStripe Subsites module:

<% with $CurrentSubsite %>
<script>
gtag('set', {
  subsite_id: '{$ID}',
  subsite_title: '{$Title}',
  subsite_domain: '{$getPrimaryDomain}'
});
</script>
<% end_with %>

5. Multi-Language Tracking

For Fluent or similar language modules:

<script>
gtag('event', 'page_view', {
  page_id: '{$ID}',
  page_locale: '{$CurrentLocale}',
  default_locale: '{$DefaultLocale}'
});
</script>

Module Configuration

Installing Analytics Modules

# Install via Composer
composer require silverstripe/google-analytics

# Run dev/build
vendor/bin/sake dev/build flush=1

SiteConfig Extension

<?php
// app/src/Extensions/SiteConfigAnalyticsExtension.php

namespace App\Extensions;

use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DataExtension;

class SiteConfigAnalyticsExtension extends DataExtension
{
    private static $db = [
        'GoogleAnalyticsID' => 'Varchar(50)',
        'GTMContainerID' => 'Varchar(50)',
    ];

    public function updateCMSFields(FieldList $fields)
    {
        $fields->addFieldsToTab('Root.Analytics', [
            TextField::create('GoogleAnalyticsID', 'Google Analytics 4 ID')
                ->setDescription('Format: G-XXXXXXXXXX'),
            TextField::create('GTMContainerID', 'GTM Container ID')
                ->setDescription('Format: GTM-XXXXXXX'),
        ]);
    }
}

Testing Integrations

Template Testing:

  • Verify variable output
  • Test conditional logic
  • Check DataObject access

Module Testing:

  • Test dev/build completion
  • Verify extension registration
  • Check CMS field additions

Elemental Testing:

  • Test block type tracking
  • Verify block visibility events
  • Check nested block handling

Next Steps

Choose your integration to get started:

Additional Resources

SilverStripe Documentation: