Grav Analytics Integrations: Setup Guide | OpsBlu Docs

Grav Analytics Integrations: Setup Guide

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

Grav is a modern flat-file CMS that stores content in Markdown files. It offers a flexible plugin architecture and Twig templating for implementing analytics integrations.

Available Integrations

Analytics Platforms

Google Analytics 4

  • Official Grav GA plugin
  • Page-level tracking
  • Custom event implementation
  • Admin exclusion options

Tag Management

Google Tag Manager

  • GTM plugin installation
  • Data layer configuration via Twig
  • Custom event triggers
  • Page type tracking

Marketing Pixels

Meta Pixel

  • Pixel implementation options
  • Event tracking configuration
  • Content tracking for articles
  • Privacy-compliant setup

Grav-Specific Integration Considerations

Flat-File Architecture

Grav's unique content storage:

  • Markdown Files: Content stored as .md files
  • YAML Frontmatter: Metadata in file headers
  • Folder Structure: URL structure matches folders
  • No Database: Fast and portable

Twig Template Integration

Implement tracking via Twig templates:

{# In templates/partials/analytics.html.twig #}

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

  gtag('config', '{{ config.plugins.google_analytics.tracking_id }}', {
    page_title: '{{ page.title }}',
    page_path: '{{ page.url }}',
    content_type: '{{ page.template }}',
    {% if page.header.author %}
    author: '{{ page.header.author }}',
    {% endif %}
    {% if page.header.category %}
    category: '{{ page.header.category|join(",") }}'
    {% endif %}
  });
</script>
{% endif %}

Page Frontmatter Tracking

Leverage Grav's frontmatter for analytics:

---
title: 'My Article'
author: 'John Doe'
category:
  - Technology
  - Tutorials
taxonomy:
  tag: [grav, cms, tutorial]
analytics:
  track_scroll: true
  content_group: 'blog'
---
{# Access frontmatter in templates #}
<script>
gtag('event', 'page_view', {
  page_title: '{{ page.title }}',
  author: '{{ page.header.author }}',
  categories: '{{ page.header.category|join(",") }}',
  tags: '{{ page.taxonomy.tag|join(",") }}',
  content_group: '{{ page.header.analytics.content_group|default("general") }}'
});
</script>

Plugin Event Hooks

Create custom tracking plugins:

<?php
// user/plugins/custom-analytics/custom-analytics.php

namespace Grav\Plugin;

use Grav\Common\Plugin;
use RocketTheme\Toolbox\Event\Event;

class CustomAnalyticsPlugin extends Plugin
{
    public static function getSubscribedEvents()
    {
        return [
            'onPageInitialized' => ['onPageInitialized', 0],
            'onTwigSiteVariables' => ['onTwigSiteVariables', 0]
        ];
    }

    public function onTwigSiteVariables(Event $e)
    {
        $page = $this->grav['page'];

        $this->grav['twig']->twig_vars['analytics_data'] = [
            'page_id' => $page->id(),
            'page_route' => $page->route(),
            'page_template' => $page->template(),
            'page_modified' => $page->modified(),
            'is_blog_post' => $page->template() === 'item'
        ];
    }
}

Blog/Collection Tracking

Track Grav blog and collections:

{# For blog listing pages #}
{% for post in page.collection %}
<article data-analytics-id="{{ post.id }}" data-analytics-title="{{ post.title }}">
  <a href="{{ post.url }}" post.id }}', '{{ post.title }}')">
    {{ post.title }}
  </a>
</article>
{% endfor %}

<script>
function trackBlogClick(postId, title) {
  gtag('event', 'blog_post_click', {
    post_id: postId,
    post_title: title,
    list_page: '{{ page.title }}'
  });
}
</script>

Modular Page Tracking

Track Grav's modular pages:

{# In modular template #}
{% for module in page.collection() %}
<section
  class="modular-{{ module.template }}"
  data-module-type="{{ module.template }}"
  data-module-title="{{ module.title }}"
>
  {% include 'modular/' ~ module.template ~ '.html.twig' %}
</section>
{% endfor %}

<script>
// Track modular section visibility
document.querySelectorAll('[data-module-type]').forEach(section => {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        gtag('event', 'module_view', {
          module_type: entry.target.dataset.moduleType,
          module_title: entry.target.dataset.moduleTitle
        });
      }
    });
  }, { threshold: 0.5 });

  observer.observe(section);
});
</script>

Integration Best Practices

1. Use Page IDs for Tracking

Grav pages have stable IDs based on folder path:

gtag('event', 'content_view', {
  content_id: '{{ page.id }}', {# Stable folder-based ID #}
  content_slug: '{{ page.slug }}', {# May change #}
  content_route: '{{ page.route }}'
});

2. Track Taxonomy

Leverage Grav's taxonomy system:

gtag('event', 'page_view', {
  page_id: '{{ page.id }}',
  categories: '{{ page.taxonomy.category|join(",") }}',
  tags: '{{ page.taxonomy.tag|join(",") }}',
  authors: '{{ page.taxonomy.author|join(",") }}'
});

3. Handle Multi-Language Sites

For Grav's multi-language support:

gtag('event', 'page_view', {
  page_id: '{{ page.id }}',
  page_language: '{{ grav.language.getActive }}',
  default_language: '{{ grav.language.getDefault }}',
  available_languages: '{{ grav.language.getLanguages|join(",") }}'
});

4. Admin Exclusion

Exclude admin sessions from analytics:

{% if not admin %}
{# Include analytics code #}
{% include 'partials/analytics.html.twig' %}
{% endif %}

5. Cache Considerations

Handle Grav's caching with analytics:

# In system/config/system.yaml
cache:
  enabled: true

# Ensure analytics scripts are not cached with stale data
# Use JavaScript to fetch dynamic data

Plugin Configuration

Installing Analytics Plugins

# Install via GPM (Grav Package Manager)
bin/gpm install google-analytics

# Or download and place in user/plugins/

Plugin Configuration

# user/config/plugins/google-analytics.yaml
enabled: true
tracking_id: G-XXXXXXXXXX
anonymize_ip: true
blocked_ips:
  - 127.0.0.1
  - 192.168.1.0/24
track_logged_in: false
debug: false

Custom Event Configuration

# user/config/plugins/custom-analytics.yaml
enabled: true
events:
  track_downloads: true
  track_outbound_links: true
  track_scroll_depth: true
  scroll_milestones: [25, 50, 75, 100]

Testing Integrations

Twig Template Testing:

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

Plugin Testing:

  • Test event hooks
  • Verify data layer output
  • Check caching behavior

Multi-Language Testing:

  • Test language switching
  • Verify locale tracking
  • Check translated content

Next Steps

Choose your integration to get started:

Additional Resources

Grav Documentation: