Overview
The data layer is the foundation of accurate Chartbeat implementation. It serves as a structured data source that prepares and organizes content metadata before Chartbeat consumes it. A well-designed data layer ensures consistent taxonomy, simplifies troubleshooting, and enables seamless integration with other analytics tools.
Why a Data Layer Matters
Consistency: Centralizes metadata in one location, ensuring all analytics tools receive identical information Maintainability: Changes to metadata structure can be made without modifying tracking code Governance: Provides a single source of truth for content taxonomy and attribution Testing: Enables easy validation of data before it reaches Chartbeat Integration: Facilitates coordination with tag managers and other marketing technology
Data Layer Architecture
Chartbeat relies on page-level metadata that describes the content being viewed. This metadata should be:
- Available before Chartbeat initialization
- Structured consistently across all pages
- Validated against defined taxonomies
- Updated dynamically for single-page applications
Required Fields
Essential Metadata Fields
| Field | Type | Description | Example | Required |
|---|---|---|---|---|
uid |
Integer | Chartbeat account ID | 12345 |
Yes |
domain |
String | Primary domain being tracked | example.com |
Yes |
sections |
String | Comma-separated section hierarchy | News,Politics,Elections |
Yes |
authors |
String | Article author(s) | Jane Smith |
Yes |
title |
String | Page or article title | Breaking News Story |
Yes |
path |
String | Canonical URL path | /news/politics/story |
Yes |
Recommended Optional Fields
| Field | Type | Description | Example |
|---|---|---|---|
contentType |
String | Type of content | article, video, gallery |
contentId |
String | Unique content identifier | article-12345 |
publishDate |
String | Publication date (ISO 8601) | 2025-12-26T10:00:00Z |
tags |
Array | Content tags or keywords | ['election', 'politics', '2024'] |
sponsorship |
String | Sponsorship or branded content flag | sponsored |
videoId |
String | Video identifier (if applicable) | video-789 |
Consent and Privacy Fields
| Field | Type | Description | Example |
|---|---|---|---|
consentGranted |
Boolean | User consent status | true or false |
noCookies |
Boolean | Cookie-less tracking flag | true |
privacyMode |
String | Privacy mode setting | standard, strict |
Data Layer Structure
Standard JavaScript Data Layer
// Global data layer object
window.chartbeatDataLayer = {
// Account configuration
uid: 12345,
domain: 'example.com',
// Content metadata
sections: 'News,Politics,Elections',
authors: 'Jane Smith,John Doe',
title: 'Election Results Coming In',
path: '/news/politics/election-results',
// Content classification
contentType: 'article',
contentId: 'article-2025-001',
publishDate: '2025-12-26T10:00:00Z',
// Additional metadata
tags: ['election', 'politics', '2024', 'breaking-news'],
sponsorship: null,
// Privacy and consent
consentGranted: true,
noCookies: false,
// Engagement settings
useCanonical: true,
useCanonicalDomain: true
};
Google Tag Manager Data Layer
// Push to GTM data layer
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'pageview',
'chartbeat': {
'uid': 12345,
'domain': 'example.com',
'sections': 'News,Politics,Elections',
'authors': 'Jane Smith',
'title': 'Election Results Coming In',
'path': '/news/politics/election-results',
'contentType': 'article',
'contentId': 'article-2025-001'
}
});
Tealium Data Layer
// Tealium UDO (Universal Data Object)
window.utag_data = {
chartbeat_uid: '12345',
chartbeat_domain: 'example.com',
chartbeat_sections: 'News,Politics,Elections',
chartbeat_authors: 'Jane Smith',
page_title: 'Election Results Coming In',
page_path: '/news/politics/election-results',
content_type: 'article',
content_id: 'article-2025-001',
publish_date: '2025-12-26T10:00:00Z'
};
Section Taxonomy Design
Hierarchical Section Structure
Chartbeat sections should follow a logical hierarchy that reflects your content organization:
Level 1: Primary Category (e.g., News, Sports, Entertainment)
Level 2: Subcategory (e.g., Politics, Local, World)
Level 3: Specific Topic (e.g., Elections, Crime, Education)
Example Taxonomy:
News→ All news contentNews,Politics→ Political newsNews,Politics,Elections→ Election coverageSports,Football,NFL→ Professional football coverage
Section Naming Conventions
Best Practices:
- Use Title Case:
News,Politics,Elections(notnews,politics,elections) - Be Concise: Keep section names short and descriptive
- Stay Consistent: Use the same naming across all pages
- Avoid Special Characters: Stick to letters, numbers, and hyphens
- Limit Depth: Maximum 3-4 levels deep for clarity
Common Section Patterns:
// Standard articles
sections: 'News,Politics'
// Subsection-specific content
sections: 'Sports,Football,NFL,Teams'
// Opinion or editorial
sections: 'Opinion,Columnists'
// Multimedia content
sections: 'Videos,News,Breaking'
// Special sections
sections: 'Special Reports,Election 2024'
Author Attribution
Author Name Formatting
Single Author:
authors: 'Jane Smith'
Multiple Authors:
authors: 'Jane Smith,John Doe'
Staff or Anonymous:
authors: 'Staff Writer'
// or
authors: 'Editorial Board'
Author Standardization
Maintain consistent author names across your CMS and analytics:
| CMS Author Field | Chartbeat Format | Notes |
|---|---|---|
Jane M. Smith |
Jane Smith |
Use simplified version |
Dr. Jane Smith |
Jane Smith |
Remove titles |
jane.smith@example.com |
Jane Smith |
Convert email to name |
Smith, Jane |
Jane Smith |
Use First Last format |
Content Type Classification
Define clear content types to segment your analytics:
// Standard content types
const contentTypes = {
ARTICLE: 'article',
VIDEO: 'video',
GALLERY: 'gallery',
INTERACTIVE: 'interactive',
PODCAST: 'podcast',
LIVE_BLOG: 'live-blog',
OPINION: 'opinion',
SPONSORED: 'sponsored'
};
// Set based on page template or CMS classification
contentType: contentTypes.ARTICLE
CMS Integration Examples
WordPress Data Layer
<!-- WordPress data layer in header.php or footer.php -->
<script type="text/javascript">
window.chartbeatDataLayer = {
uid: <?php echo get_option('chartbeat_uid', 12345); ?>,
domain: '<?php echo $_SERVER['HTTP_HOST']; ?>',
sections: '<?php
$categories = get_the_category();
$sections = array_map(function($cat) {
return $cat->name;
}, $categories);
echo implode(',', $sections);
?>',
authors: '<?php echo get_the_author(); ?>',
title: '<?php echo esc_js(get_the_title()); ?>',
path: '<?php echo parse_url(get_permalink(), PHP_URL_PATH); ?>',
contentType: '<?php echo get_post_type(); ?>',
contentId: 'post-<?php echo get_the_ID(); ?>',
publishDate: '<?php echo get_the_date('c'); ?>'
};
</script>
Drupal Data Layer
<!-- Drupal twig template -->
<script type="text/javascript">
window.chartbeatDataLayer = {
uid: {{ chartbeat_uid }},
domain: '{{ site_domain }}',
sections: '{{ node.field_section.value }}',
authors: '{{ node.field_author.value }}',
title: '{{ node.title.value|escape('js') }}',
path: '{{ node.url }}',
contentType: '{{ node.type.target_id }}',
contentId: 'node-{{ node.nid.value }}',
publishDate: '{{ node.created.value|date('c') }}'
};
</script>
Custom CMS / React SPA
// React component that sets data layer
import { useEffect } from 'react';
const ChartbeatDataLayer = ({ article }) => {
useEffect(() => {
window.chartbeatDataLayer = {
uid: process.env.CHARTBEAT_UID,
domain: window.location.hostname,
sections: article.categories.join(','),
authors: article.authors.map(a => a.name).join(','),
title: article.title,
path: article.path,
contentType: article.type,
contentId: `article-${article.id}`,
publishDate: article.publishedAt
};
// Dispatch event to notify Chartbeat of data layer update
window.dispatchEvent(new CustomEvent('chartbeatDataLayerReady'));
}, [article]);
return null;
};
export default ChartbeatDataLayer;
Single-Page Application (SPA) Considerations
Dynamic Data Layer Updates
For SPAs, update the data layer on each route change:
// React Router example
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
const useChartbeatDataLayer = (pageData) => {
const location = useLocation();
useEffect(() => {
// Update data layer
window.chartbeatDataLayer = {
...window.chartbeatDataLayer,
sections: pageData.sections,
authors: pageData.authors,
title: pageData.title,
path: location.pathname,
contentType: pageData.contentType,
contentId: pageData.id
};
// Trigger virtual page view if Chartbeat is loaded
if (typeof window.pSUPERFLY !== 'undefined') {
window.pSUPERFLY.virtualPage({
sections: pageData.sections,
authors: pageData.authors,
title: pageData.title,
path: location.pathname
});
}
}, [location, pageData]);
};
Governance Notes
Taxonomy Governance Process
Ownership and Responsibilities:
- Editorial Team: Defines and approves section taxonomy
- CMS Administrators: Maintain section mappings in CMS
- Analytics Team: Monitors data quality and reports anomalies
- Development Team: Implements and maintains data layer code
Review Cadence:
- Monthly: Quick data quality check in Chartbeat dashboard
- Quarterly: Full taxonomy audit against CMS structure
- Annually: Comprehensive review and cleanup of deprecated sections
Documentation Requirements
Maintain centralized documentation for:
- Complete section taxonomy with hierarchy
- Author name standardization rules
- Content type definitions and usage guidelines
- CMS field mappings to Chartbeat parameters
- Special case handling (sponsored content, wire articles, etc.)
Quality Assurance Procedures
Pre-Publication Checks:
- New sections approved by editorial team
- Section names follow naming conventions
- Author names standardized and consistent
- Content type correctly classified
- Metadata populates correctly in preview/staging
Post-Publication Monitoring:
- Real-Time dashboard shows correct metadata
- Section hierarchy appears as expected
- Author attribution accurate
- No "undefined" or null values
- Engagement tracking functioning properly
Validation Steps
Pre-Deployment Validation
1. Data Layer Inspection
Open browser console and verify data layer structure:
// Check data layer exists and is populated
console.log(window.chartbeatDataLayer);
// Expected output:
{
uid: 12345,
domain: "example.com",
sections: "News,Politics",
authors: "Jane Smith",
title: "Article Title",
path: "/news/politics/article",
// ... other fields
}
2. Data Type Validation
// Validate data types
console.assert(typeof window.chartbeatDataLayer.uid === 'number', 'UID should be a number');
console.assert(typeof window.chartbeatDataLayer.domain === 'string', 'Domain should be a string');
console.assert(window.chartbeatDataLayer.sections.includes(',') || window.chartbeatDataLayer.sections.length > 0, 'Sections should be populated');
3. Required Fields Check
// Check all required fields present
const requiredFields = ['uid', 'domain', 'sections', 'authors', 'title', 'path'];
const missingFields = requiredFields.filter(field => !window.chartbeatDataLayer[field]);
if (missingFields.length > 0) {
console.error('Missing required fields:', missingFields);
}
Post-Deployment Validation
Real-Time Dashboard Verification
- Navigate to Chartbeat Real-Time dashboard
- Find your test pageview in the "Now" section
- Verify metadata appears correctly:
- Section hierarchy displays as expected
- Author name matches published content
- Page title accurate
- Engagement timer incrementing
Network Request Inspection
Open browser DevTools Network tab and inspect Chartbeat ping requests:
Request URL: https://ping.chartbeat.net/ping?
h=example.com
&p=/news/politics/article
&u=12345
&d=example.com
&t=Article+Title
&a=Jane+Smith
&s=News,Politics
Verify all parameters contain expected values.
Automated Validation Script
// Chartbeat data layer validator
function validateChartbeatDataLayer() {
const dl = window.chartbeatDataLayer;
const errors = [];
const warnings = [];
// Required field validation
if (!dl.uid || typeof dl.uid !== 'number') {
errors.push('UID is required and must be a number');
}
if (!dl.domain || typeof dl.domain !== 'string') {
errors.push('Domain is required and must be a string');
}
if (!dl.sections || typeof dl.sections !== 'string') {
errors.push('Sections is required and must be a string');
}
if (!dl.authors || typeof dl.authors !== 'string') {
errors.push('Authors is required and must be a string');
}
if (!dl.title || typeof dl.title !== 'string') {
errors.push('Title is required and must be a string');
}
if (!dl.path || typeof dl.path !== 'string') {
errors.push('Path is required and must be a string');
}
// Best practice warnings
if (dl.sections && dl.sections.split(',').length > 4) {
warnings.push('Section hierarchy deeper than 4 levels may be hard to navigate');
}
if (dl.title && dl.title.length > 100) {
warnings.push('Title exceeds 100 characters, may be truncated in reports');
}
if (dl.authors && dl.authors.includes('@')) {
warnings.push('Author field appears to contain email address instead of name');
}
// Return validation results
return {
valid: errors.length === 0,
errors,
warnings
};
}
// Run validation
const validation = validateChartbeatDataLayer();
console.log('Validation Results:', validation);
Troubleshooting Common Issues
| Issue | Symptoms | Diagnosis | Resolution |
|---|---|---|---|
| Missing sections | Dashboard shows blank sections | Check data layer in console | Verify CMS populates section field; check for null/undefined values |
| Incorrect author | Wrong author in dashboard | Inspect authors parameter |
Standardize author names; check CMS author field mapping |
| Title truncation | Title cut off in reports | Check title length | Limit titles to 100 characters; use headline, not full article text |
| Section mismatch | Sections don't match CMS | Compare data layer to CMS categories | Align taxonomy between CMS and Chartbeat; document mapping rules |
| Undefined values | "undefined" appears in dashboard | Check JavaScript errors | Ensure all fields populated before Chartbeat loads; add fallback values |
| SPA data not updating | Stale metadata after navigation | Check virtualPage calls | Update data layer before triggering virtualPage; verify event timing |
| Special characters | Broken text with special chars | Check encoding | Properly escape JavaScript strings; use UTF-8 encoding |
| Multiple authors format | Authors appear as single string | Check separator format | Use comma separation: "Jane Smith,John Doe" |
Best Practices
- Centralize Data Layer: Define data layer in one location, early in page load
- Validate Before Tracking: Check all required fields present before initializing Chartbeat
- Use Consistent Naming: Maintain standardized taxonomy and author name formats
- Document Everything: Keep taxonomy documentation up to date and accessible
- Monitor Quality: Regularly audit Real-Time dashboard for data anomalies
- Test Thoroughly: Validate data layer on all content types and templates
- Handle Edge Cases: Plan for missing authors, sponsored content, wire articles
- Coordinate Teams: Ensure editorial, CMS, and analytics teams aligned on taxonomy
Data Layer Checklist
- Data layer structure defined and documented
- All required fields mapped from CMS
- Section taxonomy approved and implemented
- Author standardization rules established
- Content type classification complete
- Validation script created and tested
- Tag manager variables configured (if applicable)
- SPA virtual page view data updates working
- Edge cases documented and handled
- Team training completed on taxonomy governance
- Monitoring and alerting configured for data quality
- Documentation published and accessible