Data Layer Implementation
Sources:
- https://developers.google.com/tag-platform/tag-manager/datalayer
- https://developers.google.com/analytics/devguides/collection/ga4/ecommerce
Last Updated: 2025-01-09
Overview
The data layer is a JavaScript object that passes information from your website to Google Tag Manager. It serves as the central hub for all tracking data, enabling consistent and reliable tag configuration. This guide covers data layer fundamentals, e-commerce implementation, SPA handling, and best practices.
Data Layer Fundamentals
What is the Data Layer?
The data layer is a JavaScript array that stores data for GTM to consume:
window.dataLayer = window.dataLayer || [];
Every subsequent push into the dataLayer should be preceded with the above snippet for safety.
How It Works
- Website pushes data to
dataLayer - GTM listens for pushes
- Data becomes available via Data Layer Variables
- Tags and triggers can access the data
Basic Push Syntax
window.dataLayer.push({
'key': 'value',
'anotherKey': 'anotherValue'
});
Event Push Syntax
window.dataLayer.push({
'event': 'custom_event_name',
'eventData': 'associated data'
});
Data Layer Initialisation
Proper Setup Order
<!-- 1. Initialise data layer BEFORE GTM -->
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'pageType': 'product',
'userId': 'USER123',
'userStatus': 'logged_in'
});
</script>
<!-- 2. GTM snippet loads and reads initial data -->
<script>...</script>
Why Order Matters
- Data must be available when Container Loaded fires
- Page View triggers need access to initial data
- Prevents race conditions
Common Data Layer Patterns
Page Data
window.dataLayer.push({
'event': 'page_data',
'page': {
'type': 'product',
'category': 'Electronics',
'subcategory': 'Phones'
}
});
User Data
window.dataLayer.push({
'event': 'user_data',
'user': {
'id': 'USER123',
'status': 'logged_in',
'type': 'premium',
'lifetime_value': 1500.00
}
});
Form Submission
window.dataLayer.push({
'event': 'form_submit',
'form': {
'id': 'contact-form',
'name': 'Contact Us',
'type': 'contact'
}
});
Button Click
window.dataLayer.push({
'event': 'button_click',
'button': {
'id': 'cta-signup',
'text': 'Sign Up Now',
'location': 'hero'
}
});
GA4 E-commerce Data Layer
View Item List
window.dataLayer.push({ ecommerce: null }); // Clear previous ecommerce data
window.dataLayer.push({
'event': 'view_item_list',
'ecommerce': {
'item_list_id': 'category_phones',
'item_list_name': 'Phones',
'items': [
{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'affiliation': 'Online Store',
'index': 0,
'item_brand': 'Apple',
'item_category': 'Electronics',
'item_category2': 'Phones',
'item_list_id': 'category_phones',
'item_list_name': 'Phones',
'price': 1299.00,
'quantity': 1
},
{
'item_id': 'SKU002',
'item_name': 'Samsung Galaxy S24',
'index': 1,
'item_brand': 'Samsung',
'item_category': 'Electronics',
'item_category2': 'Phones',
'price': 999.00,
'quantity': 1
}
]
}
});
Select Item
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'select_item',
'ecommerce': {
'item_list_id': 'category_phones',
'item_list_name': 'Phones',
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'item_brand': 'Apple',
'item_category': 'Electronics',
'price': 1299.00,
'quantity': 1
}]
}
});
View Item
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'view_item',
'ecommerce': {
'currency': 'AUD',
'value': 1299.00,
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'affiliation': 'Online Store',
'item_brand': 'Apple',
'item_category': 'Electronics',
'item_category2': 'Phones',
'item_variant': '128GB Black',
'price': 1299.00,
'quantity': 1
}]
}
});
Add to Cart
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'currency': 'AUD',
'value': 1299.00,
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'item_brand': 'Apple',
'item_category': 'Electronics',
'item_variant': '128GB Black',
'price': 1299.00,
'quantity': 1
}]
}
});
Remove from Cart
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'remove_from_cart',
'ecommerce': {
'currency': 'AUD',
'value': 1299.00,
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'price': 1299.00,
'quantity': 1
}]
}
});
View Cart
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'view_cart',
'ecommerce': {
'currency': 'AUD',
'value': 2298.00,
'items': [
{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'price': 1299.00,
'quantity': 1
},
{
'item_id': 'SKU003',
'item_name': 'AirPods Pro',
'price': 399.00,
'quantity': 1
}
]
}
});
Begin Checkout
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'begin_checkout',
'ecommerce': {
'currency': 'AUD',
'value': 2298.00,
'coupon': 'SUMMER10',
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'price': 1299.00,
'quantity': 1
}]
}
});
Add Shipping Info
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'add_shipping_info',
'ecommerce': {
'currency': 'AUD',
'value': 2298.00,
'shipping_tier': 'Express',
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'price': 1299.00,
'quantity': 1
}]
}
});
Add Payment Info
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'add_payment_info',
'ecommerce': {
'currency': 'AUD',
'value': 2298.00,
'payment_type': 'Credit Card',
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'price': 1299.00,
'quantity': 1
}]
}
});
Purchase
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': 'T12345',
'affiliation': 'Online Store',
'value': 2348.00,
'tax': 213.45,
'shipping': 50.00,
'currency': 'AUD',
'coupon': 'SUMMER10',
'items': [
{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'affiliation': 'Online Store',
'coupon': 'SUMMER10',
'item_brand': 'Apple',
'item_category': 'Electronics',
'item_category2': 'Phones',
'item_variant': '128GB Black',
'price': 1299.00,
'quantity': 1
},
{
'item_id': 'SKU003',
'item_name': 'AirPods Pro',
'item_brand': 'Apple',
'item_category': 'Electronics',
'item_category2': 'Audio',
'price': 399.00,
'quantity': 1
}
]
}
});
Refund
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'refund',
'ecommerce': {
'transaction_id': 'T12345',
'value': 1299.00,
'currency': 'AUD',
'items': [{
'item_id': 'SKU001',
'item_name': 'iPhone 15',
'price': 1299.00,
'quantity': 1
}]
}
});
Single-Page Application (SPA) Handling
Virtual Pageviews
For SPAs, push virtual pageviews when routes change:
// React Router example
useEffect(() => {
window.dataLayer.push({
'event': 'virtual_pageview',
'page_path': location.pathname,
'page_title': document.title,
'page_location': window.location.href
});
}, [location]);
Data Clearing for SPAs
Clear previous page data to prevent carryover:
// Method 1: Set to undefined
window.dataLayer.push({
'event': 'virtual_pageview',
'page_path': '/new-page',
// Clear previous values
'transaction_id': undefined,
'ecommerce': undefined
});
// Method 2: Use reset function
window.dataLayer.push(function() {
this.reset();
});
window.dataLayer.push({
'event': 'virtual_pageview',
'page_path': '/new-page'
});
What to Clear
Clear on every virtual pageview:
- Previous page-scoped data
- Transaction data
- Ecommerce data
Keep persistent:
- User ID
- User status
- Session-level data
Data Layer Best Practices
Never Overwrite the Array
// BAD - Loses existing data
dataLayer = [{'key': 'value'}];
// GOOD - Preserves existing data
window.dataLayer.push({'key': 'value'});
Use Correct Casing
// BAD - Wrong casing
window.dataLayer.push({}); // lowercase 'l'
window.dataLayer.push({}); // capital 'D'
// GOOD - Correct camelCase
window.dataLayer.push({});
Quote Variable Names
// GOOD - Always use quotes
window.dataLayer.push({
'variable-name': 'value',
'anotherVariable': 'value'
});
Consistent Naming
// BAD - Inconsistent
// Page 1:
window.dataLayer.push({'user_type': 'premium'});
// Page 2:
window.dataLayer.push({'userType': 'premium'});
// GOOD - Consistent across all pages
window.dataLayer.push({'userType': 'premium'});
Clear E-commerce Data
Always clear ecommerce object before pushing:
window.dataLayer.push({ ecommerce: null });
window.dataLayer.push({
'event': 'purchase',
'ecommerce': { /* purchase data */ }
});
Avoid PII
Never push personally identifiable information:
// BAD - Contains PII
window.dataLayer.push({
'email': 'user@example.com',
'phone': '+61412345678'
});
// GOOD - Hash or pseudonymise
window.dataLayer.push({
'emailHash': 'a1b2c3d4...', // SHA-256 hash
'hasPhone': true
});
Custom Data Layer Methods
The set() Method
Store values for later retrieval:
window.dataLayer.push(function() {
this.set('lastUpdated', new Date());
});
The get() Method
Retrieve stored values:
window.dataLayer.push(function() {
var lastUpdated = this.get('lastUpdated');
console.log('Last updated:', lastUpdated);
});
The reset() Method
Clear all data layer state:
window.dataLayer.push(function() {
this.reset();
});
Debugging the Data Layer
Console Inspection
// View entire data layer
console.log(window.dataLayer);
// Find specific events
dataLayer.filter(function(item) {
return item.event === 'purchase';
});
Monitor Pushes
var originalPush = window.dataLayer.push;
window.dataLayer.push = function() {
console.log('Data Layer push:', arguments[0]);
return originalPush.apply(this, arguments);
};
GTM Preview Mode
- Enable Preview mode
- Click any event in Summary
- Open Data Layer tab
- View data layer state at that event
Data Layer Specification
Documentation Template
Document your data layer for developers:
## userType
- **Type**: String
- **Values**: 'guest', 'registered', 'premium'
- **Populated**: On all pages after user identification
- **Example**: `{'userType': 'premium'}`
- **Used by**: User Segmentation Tags, Personalisation Triggers
## ecommerce.items
- **Type**: Array of Objects
- **Required Fields**: item_id, item_name, price
- **Optional Fields**: item_brand, item_category, quantity
- **Populated**: E-commerce events only
- **Example**: See purchase event documentation