Analytics Architecture on Voog
Voog is a template-driven website builder that uses Liquid as its templating language. Unlike most closed builders, Voog exposes its template files for direct editing, giving full control over where and how analytics code is injected.
The primary injection points are:
{{ content_for_head }}-- A Liquid tag in layout templates that outputs the site's HEAD code, including any code added via the admin panel- Custom Template Editing -- Direct access to layout and page template files via Design > Code Editor
- Site Settings Code Injection -- Admin panel fields for HEAD and BODY code under Settings > Code Injection
- Voog SDK -- Client-side JavaScript SDK (
Voog.js) for interacting with page content and editor state
Template Hierarchy
Voog templates follow a layout-page hierarchy:
layouts/
default.html # Base layout with <html>, <head>, <body>
blog.html # Blog-specific layout
pages/
page.html # Standard page template
blog_article.html # Blog post template
components/
header.html # Shared header partial
footer.html # Shared footer partial
All layouts must include {{ content_for_head }} in the <head> section for Voog's admin-injected scripts to work. Analytics code can be placed directly in templates or injected via the admin panel.
Installing Tracking Scripts
Method 1: Template-Level Installation (Recommended)
Edit the base layout file via Design > Code Editor > layouts/default.html:
<!DOCTYPE html>
<html lang="{{ page.language.code }}">
<head>
<meta charset="utf-8">
<title>{{ page.title }} - {{ site.name }}</title>
{{ content_for_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-XXXXXX');
</script>
</head>
<body>
<!-- GTM noscript -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXXXXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
{{ content_for_body }}
</body>
</html>
Method 2: Admin Panel Code Injection
Navigate to Settings > Code Injection:
- Header Code -- Injected inside
<head>via the{{ content_for_head }}tag - Footer Code -- Injected before
</body>
This method does not require template editing and works for users without code editor access.
Method 3: Page-Specific Templates
Create a custom page template for pages that need different tracking:
<!-- pages/landing.html -->
{% layout "default" %}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'landing_view',
page_template: 'landing',
page_id: '{{ page.id }}'
});
</script>
{{ content_for_body }}
Data Layer Implementation
Use Liquid template variables to populate the data layer with server-rendered values:
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
platform: 'voog',
page_id: '{{ page.id }}',
page_title: '{{ page.title | escape }}',
page_path: '{{ page.path }}',
page_language: '{{ page.language.code }}',
page_template: '{{ page.layout.title | escape }}',
site_name: '{{ site.name | escape }}',
content_type: '{% if page.blog? %}blog{% elsif page.article? %}article{% else %}page{% endif %}'
});
</script>
Multilingual Site Tracking
Voog is built for multilingual sites. Each language version has its own URL structure. Track language as a dimension:
<script>
window.dataLayer = window.dataLayer || [];
// Voog exposes language data via Liquid
var langData = {
current_language: '{{ page.language.code }}',
available_languages: [
{% for lang in site.languages %}
'{{ lang.code }}'{% unless forloop.last %},{% endunless %}
{% endfor %}
],
is_default_language: {{ page.language.default? }}
};
window.dataLayer.push({
event: 'language_context',
language: langData.current_language,
language_count: langData.available_languages.length
});
</script>
Blog Article Tracking
For blog templates, extract article-specific metadata:
{% if page.article? %}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'article_view',
article_title: '{{ page.title | escape }}',
article_author: '{{ page.author | escape }}',
article_date: '{{ page.created_at | date: "%Y-%m-%d" }}',
article_tags: [
{% for tag in page.tags %}
'{{ tag.name | escape }}'{% unless forloop.last %},{% endunless %}
{% endfor %}
]
});
</script>
{% endif %}
E-commerce Tracking
Voog's e-commerce features expose product data through Liquid variables:
{% if page.product? %}
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'view_item',
ecommerce: {
items: [{
item_name: '{{ page.product.name | escape }}',
price: {{ page.product.price }},
currency: '{{ site.currency }}'
}]
}
});
</script>
{% endif %}
Common Issues
content_for_head Missing from Layout
If analytics code added via Settings > Code Injection does not appear on the live site, the layout template is missing the {{ content_for_head }} tag. Edit the layout via Design > Code Editor and add it inside the <head> section.
Liquid Escaping Breaks JavaScript
Liquid variables containing quotes or special characters can break inline JavaScript. Always use the | escape filter:
<!-- Wrong -- breaks if title contains quotes -->
<script>var title = '{{ page.title }}';</script>
<!-- Correct -->
<script>var title = '{{ page.title | escape }}';</script>
For JSON output, use | json if available or manually escape:
<script>var pageData = {{ page | json }};</script>
Multilingual URL Conflicts
Voog uses language-prefixed URLs (/en/about, /fr/about). If your analytics filters use exact path matching, the same logical page will appear as multiple paths. Normalize paths by stripping the language prefix:
var cleanPath = window.location.pathname.replace(/^\/(en|fr|de|et)\//, '/');
window.dataLayer.push({ normalized_path: cleanPath });
Template Changes Not Reflected
After editing templates via the Code Editor, changes apply immediately to the live site. However, browsers may cache the old version. Use a cache-busting parameter or hard refresh to verify changes:
https://your-site.com/?v=timestamp
Voog SDK Conflicts
The Voog SDK (Voog.js) is loaded automatically in edit mode. It modifies the DOM for inline editing. If your analytics scripts interact with content elements, they may behave differently when an admin is logged in and editing. Guard against this:
if (!window.Voog || !window.Voog.editMode) {
// Safe to run analytics -- not in edit mode
trackPageView();
}
Platform-Specific Considerations
Voog API for auditing: The Voog API (https://your-site.voog.com/admin/api/) provides REST endpoints for pages, layouts, and site structure. Use GET /admin/api/pages to enumerate all pages and GET /admin/api/layouts to inspect which templates include tracking code. Authentication uses API tokens generated in the admin panel.
Template version control: Voog does not provide built-in version control for templates. Export templates periodically via the API or maintain a local copy. Template edits are applied immediately with no rollback mechanism.
Custom domain and SSL: Voog provides free SSL on custom domains. Analytics scripts must use HTTPS. The platform serves all pages over HTTPS by default.
Editor access levels: Voog has two access tiers -- Designer (can edit templates) and Editor (content only). Only Designer-level access can modify template-level tracking code. Editor-level users can only use the admin panel code injection fields.
Voog SDK reference: The client-side SDK provides Voog.editMode (boolean), Voog.activateTool(), and content area methods. These are editor-only utilities and should not be used for analytics. They are documented at https://www.voog.com/developers/scripting/voog-js.