Data Layer Overview
A structured data layer enables dynamic X Pixel event firing with accurate conversion and user data.
Base Structure
window.xDataLayer = window.xDataLayer || {
page: {},
user: {},
product: {},
cart: {},
transaction: {}
};
E-commerce Data Layer
Product Page
window.xDataLayer.product = {
id: 'SKU_12345',
name: 'Blue Widget',
price: 49.99,
category: 'widgets',
brand: 'WidgetCo'
};
// Fire X event
twq('event', 'tw-PIXEL_ID-ViewContent', {
content_ids: [window.xDataLayer.product.id],
content_name: window.xDataLayer.product.name,
value: window.xDataLayer.product.price.toString(),
currency: 'USD'
});
Shopping Cart
window.xDataLayer.cart = {
items: [
{ id: 'SKU_12345', name: 'Blue Widget', price: 49.99, quantity: 2 },
{ id: 'SKU_67890', name: 'Red Widget', price: 59.99, quantity: 1 }
],
subtotal: 159.97,
itemCount: 3
};
Transaction
window.xDataLayer.transaction = {
id: 'ORDER_12345',
revenue: 176.97,
tax: 12.00,
shipping: 5.00,
currency: 'USD',
items: window.xDataLayer.cart.items
};
// Fire purchase event
twq('event', 'tw-PIXEL_ID-Purchase', {
value: window.xDataLayer.transaction.revenue.toString(),
currency: window.xDataLayer.transaction.currency,
transaction_id: window.xDataLayer.transaction.id,
num_items: window.xDataLayer.cart.itemCount.toString(),
content_ids: window.xDataLayer.transaction.items.map(item => item.id)
});
User Data Layer
window.xDataLayer.user = {
id: 'USER_12345',
email: '', // Will be hashed
status: 'logged_in',
segment: 'high_value'
};
// Hash and include in events
async function hashEmail(email) {
const msgBuffer = new TextEncoder().encode(email.toLowerCase().trim());
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
async function trackWithUserData() {
const hashedEmail = await hashEmail(window.xDataLayer.user.email);
twq('event', 'tw-PIXEL_ID-Purchase', {
value: '99.99',
currency: 'USD',
transaction_id: 'ORDER_12345',
email_address: hashedEmail
});
}
Helper Functions
function fireXEventFromDataLayer(eventName) {
let eventData = {};
switch(eventName) {
case 'Purchase':
eventData = {
value: window.xDataLayer.transaction?.revenue?.toString(),
currency: 'USD',
transaction_id: window.xDataLayer.transaction?.id,
num_items: window.xDataLayer.cart?.itemCount?.toString()
};
break;
case 'AddToCart':
const lastItem = window.xDataLayer.cart?.items?.slice(-1)[0];
eventData = {
content_ids: [lastItem?.id],
value: lastItem?.price?.toString(),
currency: 'USD'
};
break;
}
if (typeof twq !== 'undefined') {
twq('event', 'tw-PIXEL_ID-' + eventName, eventData);
}
}
GTM Data Layer Integration
Sync with GTM
// GTM data layer push
dataLayer.push({
'event': 'purchase',
'ecommerce': {
'purchase': {
'actionField': {
'id': 'ORDER_12345',
'revenue': '99.99'
}
}
}
});
// Sync to X data layer
window.xDataLayer.transaction = {
id: dataLayer[dataLayer.length - 1].ecommerce.purchase.actionField.id,
revenue: parseFloat(dataLayer[dataLayer.length - 1].ecommerce.purchase.actionField.revenue),
currency: 'USD'
};
Best Practices
- Initialize data layer before X Pixel
- Convert numbers to strings for value parameters
- Hash email client-side before sending
- Clear data layer on SPA navigation
- Validate data before firing events
- Document schema for team