Bolt CMS is a PHP-based CMS built on Symfony components with Twig templating. Analytics issues on Bolt typically involve Twig template inheritance (your tracking snippet not rendering due to block override logic), Symfony's HTTP cache, or Bolt extensions interfering with script output.
Bolt CMS-Specific Debugging Approach
Bolt uses Twig templates with block inheritance, so tracking code placement depends on understanding which template blocks render on which pages. The Symfony profiler (in debug mode) is your best diagnostic tool.
Enable Debug Mode for Diagnostics
# In config/bolt/config.yaml (Bolt 5) or app/config/config.yml (Bolt 4)
# Temporarily enable debug mode
debug: true
# With debug mode on, check the Symfony profiler toolbar
# Visit your site — the toolbar at the bottom shows:
# - All Twig templates rendered
# - HTTP cache status
# - Loaded extensions
# - Response headers
# Check which Twig template rendered the page
# Click the Twig icon in the debug toolbar
Verify Tracking Code in Twig Output
# Check if your analytics snippet appears in the rendered HTML
curl -s http://your-bolt-site.com/ | grep -iE "gtag|gtm|analytics" | head -5
# Check for Twig compilation errors in logs
tail -50 var/log/bolt-*.log | grep -i "twig\|template\|error"
Inspect Extension Loading
# List installed Bolt extensions
php bin/console extensions:list
# Check for extension conflicts
php bin/console debug:container --tag=bolt.extension | grep -i "analytics\|tracking"
Most Common Bolt CMS Analytics Issues
1. Twig Block Override Removing Tracking Code
Symptoms: Analytics tag present in the base template but missing from rendered pages that extend it.
Root cause: Bolt's Twig templates use block inheritance. If a child template overrides the {% block head %} or {% block javascripts %} block without calling {{ parent() }}, the parent's tracking code is lost.
Fix: Ensure child templates preserve parent blocks:
{# In your page-specific template #}
{% extends 'base.html.twig' %}
{% block javascripts %}
{{ parent() }} {# This preserves the analytics tag from base template #}
{# Add page-specific scripts here #}
{% endblock %}
Or place analytics in a dedicated block that child templates are unlikely to override:
{# In templates/base.html.twig #}
{% block analytics %}
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXX');
</script>
{% endblock %}
</head>
2. Symfony HTTP Cache Serving Stale Pages
Symptoms: Tracking code changes don't appear. Pages show old HTML for minutes or hours.
Root cause: Bolt leverages Symfony's reverse proxy cache. Cached responses won't include template changes until the cache is invalidated.
Fix:
# Clear Symfony cache
php bin/console cache:clear
# Or delete the cache directory directly
rm -rf var/cache/prod/*
# For development
rm -rf var/cache/dev/*
3. Content Type Records Missing Tracking
Symptoms: Regular pages have tracking but content type record pages (entries, products, etc.) do not.
Root cause: Bolt renders different Twig templates for different content types. If your tracking code is in page.html.twig but not in entry.html.twig or record.html.twig, those content types are untracked.
Diagnosis:
{# Add this temporarily to identify which template rendered a page #}
<!-- Template: {{ _self }} -->
Fix: Place the analytics tag in base.html.twig (the root template that all content types extend), not in individual content type templates.
4. Twig Escaping Mangling JavaScript
Symptoms: Analytics code appears in the source but has escaped characters (e.g., & instead of &).
Root cause: Twig auto-escapes output by default. If you pass the tracking snippet through a Twig variable, it gets HTML-escaped.
Fix: Use the raw filter for analytics code stored in fields:
{# If analytics code is in a Bolt field #}
{{ record.analytics_code|raw }}
{# Or disable escaping for the block #}
{% autoescape false %}
{{ analytics_snippet }}
{% endautoescape %}
5. Bolt Extension Injecting Duplicate Tags
Symptoms: Analytics loads twice. Double pageview counts.
Diagnosis:
// Check for duplicate script loads
document.querySelectorAll('script[src*="gtag"], script[src*="gtm"]').forEach((s, i) => {
console.log(`Tag #${i + 1}:`, s.src || 'inline', '| parent:', s.parentElement.tagName);
});
Fix: Check Extensions > Installed for analytics-related extensions, and disable any that duplicate your manually-added tracking code.
Environment Considerations
- Bolt 4 vs Bolt 5: Bolt 5 is a full rewrite on Symfony 5+. Config files, directory structure, and extension loading differ significantly. Check which version you are running with
php bin/console --version - Shared hosting: Bolt can run on shared hosting where you may not have CLI access. Use the admin panel at
/bolt/to clear caches instead - Composer-managed: Extensions are installed via Composer. Broken extensions can prevent the entire site from loading — check
composer.jsonif the site goes down after an extension install - SQLite or MySQL: Bolt supports both. SQLite sites on shared hosting may have file locking issues that intermittently fail to serve pages, appearing as tracking gaps
Performance Issues
- LCP Issues - Twig compilation overhead and Symfony cache warm-up delays
- CLS Issues - Layout shifts from extension-injected widgets and deferred script loading
Tracking Issues
- Events Not Firing - Debug Twig block inheritance, Symfony cache, and extension conflicts
Related Resources
- Bolt CMS documentation
- Global Issues Hub for platform-agnostic solutions