Files
gh-henkisdabro-wookstar-cla…/skills/ga4-gtm-integration/references/gtm-data-layer-ga4.md
2025-11-29 18:32:40 +08:00

480 lines
9.2 KiB
Markdown

# GTM Data Layer Implementation for GA4
## Data Layer Fundamentals
The **data layer** is a JavaScript object that acts as a bridge between your website and Google Tag Manager, holding structured data that GTM can access and send to GA4.
### Data Layer Structure
```javascript
window.dataLayer = window.dataLayer || [];
```
**Key Concepts:**
- Global JavaScript array
- Holds events and data
- GTM reads from this automatically
- Must exist BEFORE GTM container code
### Basic Data Layer Push
```javascript
dataLayer.push({
'event': 'event_name',
'parameter_key': 'parameter_value'
});
```
**Components:**
- `event`: Trigger name for GTM Custom Event triggers
- Additional keys: Data accessible via Data Layer Variables
## Event Tracking Patterns
### Pattern 1: Simple Event
**On Website:**
```javascript
dataLayer.push({
'event': 'button_click',
'button_name': 'Subscribe Now',
'button_location': 'header'
});
```
**In GTM:**
1. Create Trigger:
- Type: Custom Event
- Event name: `button_click`
2. Create Variables:
- Name: "DL - Button Name"
- Type: Data Layer Variable
- Variable Name: `button_name`
3. Create GA4 Tag:
- Event Name: `button_click`
- Parameters: `button_name``{{DL - Button Name}}`
### Pattern 2: E-commerce Event
**On Website:**
```javascript
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'items': [
{
'item_id': 'SKU_123',
'item_name': 'Blue T-Shirt',
'price': 29.99,
'quantity': 1,
'item_category': 'Apparel'
}
],
'value': 29.99,
'currency': 'USD'
}
});
```
**In GTM:**
1. Create Variable for items:
- Name: "DL - Ecommerce Items"
- Type: Data Layer Variable
- Variable Name: `ecommerce.items`
2. Create GA4 Event Tag:
- Event Name: `add_to_cart`
- Parameters:
- `items``{{DL - Ecommerce Items}}`
- `value``{{DL - Ecommerce Value}}`
- `currency``{{DL - Ecommerce Currency}}`
### Pattern 3: Purchase Event (Complete)
**On Website:**
```javascript
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'transaction_id': 'T_12345',
'affiliation': 'Online Store',
'value': 99.98,
'currency': 'USD',
'tax': 8.00,
'shipping': 5.00,
'coupon': 'SUMMER20',
'items': [
{
'item_id': 'SKU_123',
'item_name': 'Blue T-Shirt',
'price': 29.99,
'quantity': 2,
'item_category': 'Apparel',
'item_brand': 'MyBrand'
},
{
'item_id': 'SKU_124',
'item_name': 'Black Hat',
'price': 20.00,
'quantity': 2,
'item_category': 'Accessories'
}
]
}
});
```
**In GTM:**
Create Data Layer Variables for:
- `ecommerce.transaction_id`
- `ecommerce.value`
- `ecommerce.currency`
- `ecommerce.tax`
- `ecommerce.shipping`
- `ecommerce.items`
Create GA4 Event Tag mapping all parameters.
### Pattern 4: Form Submission
**On Website:**
```javascript
document.getElementById('contact-form').addEventListener('submit', function(e) {
e.preventDefault();
dataLayer.push({
'event': 'form_submit',
'form_name': 'Contact Form',
'form_id': 'contact-form',
'form_destination': '/thank-you',
'user_email_domain': document.getElementById('email').value.split('@')[1]
});
// Then submit form
this.submit();
});
```
### Pattern 5: Video Tracking
**On Website:**
```javascript
// When video starts
dataLayer.push({
'event': 'video_start',
'video_title': 'Product Demo',
'video_duration': 180,
'video_id': 'demo_v1'
});
// When video completes
dataLayer.push({
'event': 'video_complete',
'video_title': 'Product Demo',
'video_percent': 100,
'video_id': 'demo_v1'
});
```
## Advanced Patterns
### Pattern 6: User Authentication
**On Login:**
```javascript
dataLayer.push({
'event': 'login',
'method': 'email',
'user_id': 'user_12345',
'user_tier': 'premium',
'years_customer': 3
});
```
**On Logout:**
```javascript
dataLayer.push({
'event': 'logout',
'user_id': null // Clear user ID
});
```
### Pattern 7: Page Data (For SPAs)
**On Route Change (Single Page Apps):**
```javascript
// React example
useEffect(() => {
dataLayer.push({
'event': 'virtual_page_view',
'page_path': window.location.pathname,
'page_title': document.title,
'page_category': 'products'
});
}, [location]);
```
### Pattern 8: Search Tracking
**On Search:**
```javascript
dataLayer.push({
'event': 'search',
'search_term': searchQuery,
'search_results_count': resultsCount,
'search_category': selectedCategory
});
```
## Data Layer Variable Types in GTM
### Type 1: Simple Data Layer Variable
**Configuration:**
- **Variable Type:** Data Layer Variable
- **Data Layer Variable Name:** `product_id`
- **Data Layer Version:** Version 2
**Usage:** `{{DL - Product ID}}`
### Type 2: Nested Object Access
**For Nested Data:**
```javascript
dataLayer.push({
'ecommerce': {
'value': 99.99,
'items': [...]
}
});
```
**Variable Configuration:**
- **Variable Name:** "DL - Ecommerce Value"
- **Type:** Data Layer Variable
- **Variable Name:** `ecommerce.value`
### Type 3: Array Access
**For Array Elements:**
```javascript
dataLayer.push({
'items': [
{'item_id': 'SKU_123'},
{'item_id': 'SKU_124'}
]
});
```
**Variable for First Item:**
- **Variable Name:** `items.0.item_id` (first array element)
**Better:** Pass entire `items` array to GA4 event parameter
## Timing and Order
### Rule 1: Data Layer BEFORE GTM Container
```html
<script>
window.dataLayer = window.dataLayer || [];
// Can push initial page data here
dataLayer.push({
'page_type': 'product',
'user_tier': 'premium'
});
</script>
<!-- GTM Container Code -->
<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
```
### Rule 2: Event Push AFTER User Action
```javascript
// CORRECT
button.addEventListener('click', function() {
dataLayer.push({
'event': 'button_click',
'button_name': 'Subscribe'
});
});
// WRONG - Fires on page load before click
dataLayer.push({
'event': 'button_click',
'button_name': 'Subscribe'
});
```
### Rule 3: Clear ecommerce Before Push
**For E-commerce Events:**
```javascript
// Clear previous ecommerce data
dataLayer.push({ ecommerce: null });
// Push new ecommerce data
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {
'items': [...]
}
});
```
**Why:** Prevents old ecommerce data from persisting
## SPA (Single Page Application) Patterns
### React Example
```javascript
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function App() {
const location = useLocation();
useEffect(() => {
// Track virtual page view on route change
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'virtual_page_view',
'page_path': location.pathname,
'page_title': document.title
});
}, [location]);
return <div>...</div>;
}
```
### Vue.js Example
```javascript
// In router/index.js
router.afterEach((to, from) => {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'virtual_page_view',
'page_path': to.path,
'page_title': to.meta.title || document.title
});
});
```
## Debugging Data Layer
### Console Debugging
```javascript
// View entire data layer
console.log(window.dataLayer);
// View last event pushed
console.log(window.dataLayer[window.dataLayer.length - 1]);
// Listen for pushes
var originalPush = window.dataLayer.push;
window.dataLayer.push = function() {
console.log('Data Layer Push:', arguments);
return originalPush.apply(this, arguments);
};
```
### GTM Preview Mode
**Steps:**
1. Click Preview in GTM
2. Interact with website
3. Tag Assistant shows:
- **Data Layer** tab with all pushed events
- Event details and parameters
- Values of variables at time of event
## Common Mistakes
### Mistake 1: Pushing Empty Events
```javascript
// BAD - No data
dataLayer.push({
'event': 'button_click'
});
// GOOD - Include context
dataLayer.push({
'event': 'button_click',
'button_name': 'Subscribe',
'button_location': 'header'
});
```
### Mistake 2: Not Clearing ecommerce
```javascript
// BAD - Old ecommerce data persists
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {...}
});
// GOOD
dataLayer.push({ ecommerce: null });
dataLayer.push({
'event': 'add_to_cart',
'ecommerce': {...}
});
```
### Mistake 3: Using Reserved Keys
**Avoid These Keys:**
- `gtm` (reserved by GTM)
- `google_tag_manager` (reserved)
- `event` (only for trigger names)
### Mistake 4: Wrong Data Types
```javascript
// BAD - String when should be number
dataLayer.push({
'event': 'purchase',
'value': '99.99' // String
});
// GOOD
dataLayer.push({
'event': 'purchase',
'value': 99.99 // Number
});
```
## Best Practices
1. **Initialize Early:** Create `window.dataLayer` before GTM container
2. **Consistent Naming:** Use snake_case for event and parameter names
3. **Clear ecommerce:** Always clear before pushing new ecommerce data
4. **Document Events:** Maintain documentation of all custom events
5. **Test Thoroughly:** Use GTM Preview mode to verify data layer pushes
6. **Avoid PII:** Don't push personal data (emails, names, addresses)
7. **Use Structured Data:** Follow GA4 recommended event structures