Initial commit
This commit is contained in:
572
skills/gtm-datalayer/references/datalayer-best-practices.md
Normal file
572
skills/gtm-datalayer/references/datalayer-best-practices.md
Normal file
@@ -0,0 +1,572 @@
|
||||
# Data Layer Best Practices
|
||||
|
||||
## Overview
|
||||
|
||||
The data layer is a JavaScript object used by Google Tag Manager and gtag.js to pass information to tags. Events or variables can be passed via the data layer, and triggers can be set up based on the values of variables. This guide covers best practices for implementing and maintaining the data layer.
|
||||
|
||||
## Installation and Setup
|
||||
|
||||
### Proper Data Layer Initialization
|
||||
|
||||
The data layer must be established before the Tag Manager or Google tag snippet loads:
|
||||
|
||||
```html
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
</script>
|
||||
<!-- 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>
|
||||
<!-- End Google Tag Manager -->
|
||||
```
|
||||
|
||||
### Gtag.js Installation
|
||||
|
||||
For gtag.js implementations:
|
||||
|
||||
```html
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments)};
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'TAG_ID');
|
||||
</script>
|
||||
```
|
||||
|
||||
## How Data Layer Information is Processed
|
||||
|
||||
Tag Manager processes data layer messages on a first-in, first-out (FIFO) basis:
|
||||
|
||||
1. Each message is processed one at a time, in the order received
|
||||
2. If a message is an event, any tags with trigger conditions that have been met will fire before Tag Manager moves to the next message
|
||||
3. `gtag()` or `dataLayer.push()` calls queue messages for processing after all pending messages
|
||||
4. Updated data layer values are not guaranteed to be available for the next event
|
||||
|
||||
### Event Handling Pattern
|
||||
|
||||
To ensure data availability, add an event name to messages and listen for that event with a Custom Event trigger:
|
||||
|
||||
```javascript
|
||||
// Push data with a custom event
|
||||
dataLayer.push({
|
||||
'event': 'userData',
|
||||
'userId': '12345',
|
||||
'userType': 'premium'
|
||||
});
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Never Overwrite the dataLayer Variable
|
||||
|
||||
**Bad:**
|
||||
|
||||
```javascript
|
||||
// This overwrites existing values!
|
||||
dataLayer = [{'item': 'value'}];
|
||||
```
|
||||
|
||||
**Good:**
|
||||
|
||||
```javascript
|
||||
// Initialize at the top of the page
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
// Then use push() to add values
|
||||
dataLayer.push({'item': 'value'});
|
||||
```
|
||||
|
||||
### 2. Use Correct Casing
|
||||
|
||||
The `dataLayer` object name is case-sensitive:
|
||||
|
||||
**Bad:**
|
||||
|
||||
```javascript
|
||||
datalayer.push({'pageTitle': 'Home'}); // lowercase 'l'
|
||||
DataLayer.push({'pageTitle': 'Home'}); // capital 'D'
|
||||
```
|
||||
|
||||
**Good:**
|
||||
|
||||
```javascript
|
||||
dataLayer.push({'pageTitle': 'Home'}); // correct camelCase
|
||||
```
|
||||
|
||||
### 3. Use Proper Quote Marks
|
||||
|
||||
All data layer variable names should be enclosed in quotes:
|
||||
|
||||
**Bad:**
|
||||
|
||||
```javascript
|
||||
dataLayer.push({new-variable: 'value'}); // No quotes
|
||||
dataLayer.push({newVariable: 'value'}); // No quotes (though valid JS)
|
||||
```
|
||||
|
||||
**Good:**
|
||||
|
||||
```javascript
|
||||
dataLayer.push({'new-variable': 'value'}); // Proper quotes
|
||||
dataLayer.push({'newVariable': 'value'}); // Proper quotes
|
||||
```
|
||||
|
||||
### 4. Keep Variable Names Consistent Across Pages
|
||||
|
||||
Use consistent naming conventions for the same concept across all pages:
|
||||
|
||||
**Bad:**
|
||||
|
||||
```javascript
|
||||
// Homepage:
|
||||
dataLayer.push({'visitorType': 'low-value'});
|
||||
|
||||
// Checkout Page:
|
||||
dataLayer.push({'visitor_type': 'high-value'}); // Different naming!
|
||||
```
|
||||
|
||||
**Good:**
|
||||
|
||||
```javascript
|
||||
// Homepage:
|
||||
dataLayer.push({'visitorType': 'low-value'});
|
||||
|
||||
// Checkout Page:
|
||||
dataLayer.push({'visitorType': 'high-value'}); // Consistent naming
|
||||
```
|
||||
|
||||
## Using the Data Layer with Event Handlers
|
||||
|
||||
### Sending Events
|
||||
|
||||
Use the `event` key to initiate sending events:
|
||||
|
||||
```javascript
|
||||
dataLayer.push({'event': 'event_name'});
|
||||
```
|
||||
|
||||
### Event with Button Click
|
||||
|
||||
```html
|
||||
<button onclick="dataLayer.push({'event': 'login'});">Login</button>
|
||||
```
|
||||
|
||||
### Dynamic Data Layer Variables
|
||||
|
||||
Push variables dynamically to capture information:
|
||||
|
||||
```javascript
|
||||
dataLayer.push({'variable_name': 'variable_value'});
|
||||
```
|
||||
|
||||
#### Example: Form Value Capture
|
||||
|
||||
```javascript
|
||||
// Capture color selection
|
||||
dataLayer.push({'color': 'red'});
|
||||
```
|
||||
|
||||
## Advanced Patterns
|
||||
|
||||
### Pushing Multiple Variables and Events
|
||||
|
||||
You can push multiple variables and events simultaneously:
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'color': 'red',
|
||||
'conversionValue': 50,
|
||||
'event': 'customize'
|
||||
});
|
||||
```
|
||||
|
||||
### Persisting Data Layer Variables Across Pages
|
||||
|
||||
To persist data layer variables between pages:
|
||||
|
||||
1. Call `dataLayer.push()` on each page load after data layer instantiation
|
||||
2. Place the push above the GTM container code for immediate availability
|
||||
|
||||
```html
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
dataLayer.push({
|
||||
'event': 'Pageview',
|
||||
'pagePath': 'https://www.example.com/products',
|
||||
'pageTitle': 'Product Catalog',
|
||||
'visitorType': 'customer'
|
||||
});
|
||||
</script>
|
||||
<!-- Google Tag Manager -->
|
||||
<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXXXX');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
```
|
||||
|
||||
**Important:** Variables persist only as long as the visitor remains on the current page. Variables relevant across pages must be declared in the data layer on each page.
|
||||
|
||||
## Custom Data Layer Methods
|
||||
|
||||
### The set() Method
|
||||
|
||||
Set values to retrieve later:
|
||||
|
||||
```javascript
|
||||
window.dataLayer.push(function() {
|
||||
this.set('time', new Date());
|
||||
});
|
||||
```
|
||||
|
||||
### The get() Method
|
||||
|
||||
Retrieve values that were set:
|
||||
|
||||
```javascript
|
||||
window.dataLayer.push(function() {
|
||||
const existingTime = this.get('time');
|
||||
if (existingTime !== null) {
|
||||
// Value exists, use it
|
||||
} else {
|
||||
// Value doesn't exist
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### The reset() Method
|
||||
|
||||
Reset the data in the data layer (useful for single-page applications):
|
||||
|
||||
```javascript
|
||||
window.dataLayer.push(function() {
|
||||
this.reset();
|
||||
});
|
||||
```
|
||||
|
||||
## Renaming the Data Layer
|
||||
|
||||
### For gtag.js
|
||||
|
||||
Add a query parameter named "l" to set a new data layer name:
|
||||
|
||||
```html
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID&l=myNewName"></script>
|
||||
<script>
|
||||
window.myNewName = window.myNewName || [];
|
||||
function gtag(){myNewName.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'TAG_ID');
|
||||
</script>
|
||||
```
|
||||
|
||||
### For Tag Manager
|
||||
|
||||
Replace the data layer parameter value in the container snippet:
|
||||
|
||||
```html
|
||||
<!-- 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','myNewName','GTM-XXXXXX');</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
```
|
||||
|
||||
Update all references to match the new name:
|
||||
|
||||
```javascript
|
||||
<script>
|
||||
myNewName = window.myNewName || [];
|
||||
myNewName.push({'variable_name': 'variable_value'});
|
||||
</script>
|
||||
```
|
||||
|
||||
## Common Data Layer Patterns
|
||||
|
||||
### Page View Data
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'event': 'pageview',
|
||||
'page': {
|
||||
'path': '/products/shoes',
|
||||
'title': 'Shoes | My Store',
|
||||
'category': 'Products'
|
||||
},
|
||||
'user': {
|
||||
'id': 'USER123',
|
||||
'status': 'logged_in',
|
||||
'type': 'premium'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### User Interaction
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'event': 'button_click',
|
||||
'element': {
|
||||
'id': 'cta-button',
|
||||
'text': 'Get Started',
|
||||
'destination': '/signup'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Form Submission
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'event': 'form_submission',
|
||||
'form': {
|
||||
'id': 'contact-form',
|
||||
'name': 'Contact Us',
|
||||
'fields': 5
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Video Tracking
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'event': 'video_start',
|
||||
'video': {
|
||||
'title': 'Product Demo',
|
||||
'duration': 120,
|
||||
'provider': 'youtube',
|
||||
'url': 'https://youtube.com/watch?v=xxx'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### 1. Overwriting dataLayer
|
||||
|
||||
**Problem:** Using direct assignment instead of push
|
||||
|
||||
```javascript
|
||||
// Wrong
|
||||
dataLayer = [{'item': 'value'}];
|
||||
```
|
||||
|
||||
**Solution:** Always use push after initialization
|
||||
|
||||
```javascript
|
||||
// Correct
|
||||
dataLayer.push({'item': 'value'});
|
||||
```
|
||||
|
||||
#### 2. Case Sensitivity
|
||||
|
||||
**Problem:** Incorrect casing
|
||||
|
||||
```javascript
|
||||
datalayer.push({'pageTitle': 'Home'}); // Wrong
|
||||
```
|
||||
|
||||
**Solution:** Use correct camelCase
|
||||
|
||||
```javascript
|
||||
dataLayer.push({'pageTitle': 'Home'}); // Correct
|
||||
```
|
||||
|
||||
#### 3. Missing Quotes
|
||||
|
||||
**Problem:** Variable names without quotes
|
||||
|
||||
```javascript
|
||||
dataLayer.push({pageTitle: 'Home'}); // Can cause issues
|
||||
```
|
||||
|
||||
**Solution:** Always use quotes
|
||||
|
||||
```javascript
|
||||
dataLayer.push({'pageTitle': 'Home'}); // Better
|
||||
```
|
||||
|
||||
#### 4. Inconsistent Variable Names
|
||||
|
||||
**Problem:** Using different names for the same concept
|
||||
|
||||
```javascript
|
||||
// Page 1
|
||||
dataLayer.push({'user_type': 'premium'});
|
||||
|
||||
// Page 2
|
||||
dataLayer.push({'userType': 'premium'});
|
||||
```
|
||||
|
||||
**Solution:** Document and enforce naming conventions
|
||||
|
||||
```javascript
|
||||
// All pages
|
||||
dataLayer.push({'userType': 'premium'});
|
||||
```
|
||||
|
||||
## Data Layer Structure Best Practices
|
||||
|
||||
### Use Nested Objects for Organization
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'event': 'purchase',
|
||||
'transaction': {
|
||||
'id': 'T12345',
|
||||
'revenue': 99.99,
|
||||
'tax': 9.99,
|
||||
'shipping': 5.00
|
||||
},
|
||||
'customer': {
|
||||
'id': 'C67890',
|
||||
'type': 'returning',
|
||||
'lifetime_value': 1500.00
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Use Arrays for Multiple Similar Items
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'event': 'product_impressions',
|
||||
'products': [
|
||||
{'id': 'P1', 'name': 'Blue Shoes', 'price': 49.99},
|
||||
{'id': 'P2', 'name': 'Red Shoes', 'price': 59.99},
|
||||
{'id': 'P3', 'name': 'Green Shoes', 'price': 54.99}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
### Use Clear, Descriptive Names
|
||||
|
||||
**Bad:**
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'e': 'clk',
|
||||
'v': '100',
|
||||
't': 'btn'
|
||||
});
|
||||
```
|
||||
|
||||
**Good:**
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'event': 'button_click',
|
||||
'value': '100',
|
||||
'element_type': 'button'
|
||||
});
|
||||
```
|
||||
|
||||
## Testing and Validation
|
||||
|
||||
### 1. Use Debug Mode
|
||||
|
||||
Enable debug mode in Tag Manager to verify data layer pushes in real-time.
|
||||
|
||||
### 2. Console Logging
|
||||
|
||||
Check data layer contents in the browser console:
|
||||
|
||||
```javascript
|
||||
console.log(window.dataLayer);
|
||||
```
|
||||
|
||||
### 3. Data Layer Checker Extensions
|
||||
|
||||
Use browser extensions like:
|
||||
|
||||
- Google Tag Assistant
|
||||
- dataLayer Checker
|
||||
- Tag Manager/Analytics Debugger
|
||||
|
||||
### 4. Preview Mode
|
||||
|
||||
Always test changes in Tag Manager Preview mode before publishing.
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### 1. Push Data Before It's Needed
|
||||
|
||||
Push data layer variables before the tags that need them fire.
|
||||
|
||||
### 2. Avoid Excessive Pushes
|
||||
|
||||
Consolidate data into single pushes when possible:
|
||||
|
||||
**Bad:**
|
||||
|
||||
```javascript
|
||||
dataLayer.push({'userId': '123'});
|
||||
dataLayer.push({'userType': 'premium'});
|
||||
dataLayer.push({'event': 'user_data'});
|
||||
```
|
||||
|
||||
**Good:**
|
||||
|
||||
```javascript
|
||||
dataLayer.push({
|
||||
'userId': '123',
|
||||
'userType': 'premium',
|
||||
'event': 'user_data'
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Don't Push Unnecessarily Large Data
|
||||
|
||||
Avoid pushing very large arrays or objects that won't be used.
|
||||
|
||||
### 4. Clear Data for SPAs
|
||||
|
||||
For single-page applications, reset the data layer between virtual page views:
|
||||
|
||||
```javascript
|
||||
window.dataLayer.push(function() {
|
||||
this.reset();
|
||||
});
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
### Maintain a Data Layer Specification
|
||||
|
||||
Document all data layer variables:
|
||||
|
||||
- Variable name
|
||||
- Data type
|
||||
- When it's populated
|
||||
- Example values
|
||||
- Pages where it appears
|
||||
- Tags/triggers that use it
|
||||
|
||||
### Example Documentation Format
|
||||
|
||||
```markdown
|
||||
## userType
|
||||
|
||||
- **Type:** String
|
||||
- **Values:** 'guest', 'registered', 'premium'
|
||||
- **Populated:** On all pages after user identification
|
||||
- **Example:** `{'userType': 'premium'}`
|
||||
- **Used by:** User Segmentation Tags, Personalization Triggers
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [Google Tag Manager Data Layer Documentation](https://developers.google.com/tag-platform/tag-manager/datalayer)
|
||||
- [Data Layer Best Practices (Google Support)](https://support.google.com/tagmanager/answer/6164391)
|
||||
- [GTM Help Center](https://support.google.com/tagmanager)
|
||||
Reference in New Issue
Block a user