Bolt CMS is a Symfony-based content management system that uses Twig templating, Doctrine ORM, and Composer for dependency management. Since Bolt 5, the platform is a standard Symfony application, meaning analytics integrations follow Symfony conventions with Bolt-specific template variables and content type awareness.
Integration Architecture
Bolt CMS provides three integration paths:
- Twig Templates -- Edit your theme's base template (typically
base.html.twigor_header.html.twig) in/public/theme/yourtheme/. Bolt uses Twig template inheritance, so tracking code in the base template appears on all pages. - Extensions -- Bolt extensions are Composer packages. Install via
composer requireand configure through the Bolt admin at/bolt/extensions. - Symfony Bundles -- Since Bolt 5 is a Symfony app, any Symfony bundle compatible with the framework version can be installed. This includes bundles for server-side analytics.
Available Integrations
Analytics Platforms
- Twig base template injection (direct gtag.js)
- GTM-based GA4 (recommended)
- Symfony event listener for server-side tracking
Tag Management
- Base Twig template
<head>block - Bolt extension for admin-configurable GTM ID
Marketing Pixels
- Via GTM container (recommended)
- Twig template head injection
Twig Template Integration
Edit your theme's base template to add GTM. Bolt themes use Twig block inheritance:
{# public/theme/yourtheme/base.html.twig #}
<!DOCTYPE html>
<html lang="{{ app.request.locale }}">
<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({
'pageType': '{{ record.contentType|default("page") }}',
'contentTitle': '{{ record.title|default("")|e("js") }}',
'contentSlug': '{{ record.slug|default("")|e("js") }}',
'locale': '{{ app.request.locale }}'
});
</script>
{% block head %}{% endblock %}
</head>
<body>
<!-- GTM noscript -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
{% block body %}{% endblock %}
</body>
</html>
Data Layer with Bolt Content Types
Bolt's content type system (defined in config/bolt/contenttypes.yaml) provides structured data that maps well to analytics dimensions:
{# Data layer for a record page #}
{% if record is defined %}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'contentType': '{{ record.definition.name }}',
'contentId': '{{ record.id }}',
'author': '{{ record.author.displayName|e("js") }}',
'publishDate': '{{ record.publishedAt|date("Y-m-d") }}',
'status': '{{ record.status }}'
});
</script>
{% endif %}
Platform Limitations
No admin UI for script injection. Unlike WordPress or Shopify, Bolt has no built-in "header scripts" field in the admin panel. All tracking code must be added via Twig templates or extensions. Non-technical users cannot add or modify tracking without developer access.
Template caching. Bolt caches compiled Twig templates. After editing templates, clear the cache with php bin/console cache:clear or via the admin at /bolt/clearcache. Changes will not appear until the cache is cleared.
Extension ecosystem is small. Bolt's extension marketplace has far fewer options than WordPress or Drupal. There is no widely-adopted GTM extension -- most implementations use direct Twig template editing.
Symfony profiler in dev mode. When Bolt runs in APP_ENV=dev mode, the Symfony debug toolbar injects its own JavaScript. This can interfere with tracking script testing. Always test analytics in APP_ENV=prod mode.
Performance Considerations
- Symfony overhead. Bolt 5 runs on Symfony, which has higher baseline memory usage than flat-file CMS platforms. However, Symfony's HTTP cache and reverse proxy support (Varnish) can offset this for static content pages.
- Twig compilation. Data layer logic in Twig templates compiles to PHP on first load. Keep template logic simple -- pre-compute complex values in a Twig extension or Symfony service rather than in the template.
- Doctrine queries. Accessing
record.authorin data layer templates may trigger additional Doctrine ORM queries. Use Bolt's eager loading configuration to minimize N+1 query issues.
Recommended Integration Priority
- Add GTM to base Twig template -- Single container, all pages
- Build content-type-aware data layer -- Map Bolt content types to GA4 content groups
- Configure GA4 via GTM -- Use data layer variables for custom dimensions
- Add Meta Pixel via GTM -- Map content engagement to Meta standard events
Next Steps
For general integration concepts, see the integrations overview.