Data Layer Overview
The data layer is a JavaScript object that stores structured data for tag management systems. For Google Ads, it enables dynamic conversion values, enhanced conversions, and remarketing parameters.
Base Data Layer Structure
Initialize Before GTM
Place this code before the Google Tag Manager snippet:
window.dataLayer = window.dataLayer || [];
Page-Level Data
Set on page load for all pages:
window.dataLayer = window.dataLayer || [];
dataLayer.push({
'pageType': 'homepage', // homepage, product, cart, checkout, confirmation
'userLoggedIn': true,
'userId': 'USER_12345',
'userEmail': 'user@example.com' // for enhanced conversions
});
E-commerce Data Layer
Product Detail Page
dataLayer.push({
'event': 'view_item',
'ecommerce': {
'value': 49.99,
'currency': 'USD',
'items': [{
'item_id': 'SKU_12345',
'item_name': 'Blue Widget',
'item_category': 'Widgets',
'item_brand': 'WidgetCo',
'price': 49.99
}]
}
});
Add to Cart
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'value': 49.99,
'currency': 'USD',
'items': [{
'item_id': 'SKU_12345',
'item_name': 'Blue Widget',
'quantity': 1,
'price': 49.99
}]
}
});
Purchase / Conversion
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': 'ORDER_12345',
'value': 149.99,
'tax': 10.00,
'shipping': 5.00,
'currency': 'USD',
'items': [{
'item_id': 'SKU_12345',
'item_name': 'Blue Widget',
'quantity': 2,
'price': 49.99
}, {
'item_id': 'SKU_67890',
'item_name': 'Red Widget',
'quantity': 1,
'price': 50.00
}]
}
});
Lead Generation Data Layer
Form Start
dataLayer.push({
'event': 'form_start',
'formName': 'contact_form',
'formLocation': 'homepage'
});
Form Submit
dataLayer.push({
'event': 'form_submit',
'formName': 'contact_form',
'formType': 'contact',
'leadValue': 50.00 // estimated lead value
});
Conversion with User Data
dataLayer.push({
'event': 'generate_lead',
'conversionValue': 50.00,
'user_data': {
'email': 'user@example.com',
'phone': '+15551234567',
'address': {
'first_name': 'John',
'last_name': 'Doe',
'city': 'New York',
'region': 'NY',
'postal_code': '10001',
'country': 'US'
}
}
});
Dynamic Remarketing Data Layer
Retail
dataLayer.push({
'google_tag_params': {
'ecomm_prodid': ['SKU_12345', 'SKU_67890'],
'ecomm_pagetype': 'product', // home, searchresults, product, cart, purchase, other
'ecomm_totalvalue': 49.99
}
});
Travel
dataLayer.push({
'google_tag_params': {
'travel_destid': 'NYC',
'travel_originid': 'LAX',
'travel_pagetype': 'conversionintent', // home, searchresults, offerdetail, conversionintent, conversion
'travel_totalvalue': 599.00
}
});
Real Estate
dataLayer.push({
'google_tag_params': {
'listing_id': 'PROP_12345',
'listing_pagetype': 'offerdetail', // home, searchresults, offerdetail, conversionintent, conversion
'listing_totalvalue': 450000
}
});
GTM Variable Configuration
Create Data Layer Variables
In Google Tag Manager, create variables to read from the data layer:
- DLV - Transaction ID:
ecommerce.transaction_id - DLV - Purchase Value:
ecommerce.value - DLV - Currency:
ecommerce.currency - DLV - User Email:
user_data.email - DLV - User Phone:
user_data.phone - DLV - Items:
ecommerce.items
Use Variables in Tags
Reference these variables in Google Ads tags:
- Conversion Value:
{{DLV - Purchase Value}} - Currency Code:
{{DLV - Currency}} - Transaction ID:
{{DLV - Transaction ID}} - Order ID:
{{DLV - Transaction ID}}
Enhanced Conversions Data Layer
Manual User Data
dataLayer.push({
'event': 'conversion',
'enhanced_conversion_data': {
'email': 'user@example.com',
'phone_number': '+15551234567',
'first_name': 'John',
'last_name': 'Doe',
'street': '123 Main St',
'city': 'New York',
'region': 'NY',
'postal_code': '10001',
'country': 'US'
}
});
GTM Enhanced Conversions Setup
- Enable Enhanced Conversions in Google Ads tag
- Select "Manual" mode
- Map data layer variables:
- Email:
enhanced_conversion_data.email - Phone:
enhanced_conversion_data.phone_number - First Name:
enhanced_conversion_data.first_name - Last Name:
enhanced_conversion_data.last_name - Street:
enhanced_conversion_data.street - City:
enhanced_conversion_data.city - Region:
enhanced_conversion_data.region - Postal Code:
enhanced_conversion_data.postal_code - Country:
enhanced_conversion_data.country
- Email:
Server-Side Data Layer
For server-side GTM implementations:
// Server-side data layer push
const dataLayer = {
'event': 'purchase',
'transaction_id': orderId,
'value': orderTotal,
'currency': 'USD',
'user_data': {
'email_address': userEmail,
'phone_number': userPhone,
'address': {
'first_name': firstName,
'last_name': lastName,
'city': city,
'region': state,
'postal_code': zip,
'country': country
}
}
};
Testing Data Layer
Chrome Console
Verify data layer contents:
// View entire data layer
console.log(window.dataLayer);
// View latest push
console.log(window.dataLayer[window.dataLayer.length - 1]);
// Filter by event
window.dataLayer.filter(item => item.event === 'purchase');
GTM Preview Mode
- Enable Preview mode in GTM
- Navigate through site actions
- Check "Data Layer" tab for each event
- Verify variables populate correctly
Google Tag Assistant
- Install Tag Assistant Chrome extension
- Enable recording
- Complete conversion action
- Verify data layer values in tag details
Best Practices
- Initialize data layer before GTM container code
- Use consistent naming conventions (snake_case or camelCase)
- Push events for user interactions, not just page loads
- Include transaction_id for all purchase events
- Hash sensitive data server-side before pushing to data layer (for PII compliance)
- Document your data layer specification for developers
- Validate data layer structure in staging before production
- Use server-side tagging for sensitive data when possible
- Clear ecommerce object between events:
dataLayer.push({ 'ecommerce': null }); // Clear previous ecommerce object
dataLayer.push({
'event': 'purchase',
'ecommerce': {
// new ecommerce data
}
});
Common Pitfalls
- Not clearing ecommerce object between events (causes duplicate data)
- Pushing data layer after GTM loads (GTM misses the event)
- Inconsistent currency codes
- Missing transaction IDs (causes duplicate conversions)
- Not hashing PII before client-side data layer pushes
- Hardcoding values instead of using dynamic server variables