Overview
A structured data layer is essential for Adobe Analytics implementations, serving as the contract between your website and Adobe Launch (Tags). It standardizes how page context, user data, and transaction information are exposed, enabling consistent prop/eVar mapping without fragile DOM scraping.
Data Layer Architecture
Adobe Client Data Layer (ACDL)
Adobe's recommended approach for Experience Platform integration:
// Initialize the ACDL
window.adobeDataLayer = window.adobeDataLayer || [];
// Push page context
adobeDataLayer.push({
page: {
pageInfo: {
pageName: "Electronics | Headphones | Product Detail",
pageType: "product",
siteSection: "Electronics",
server: "www.example.com",
language: "en-US"
},
category: {
primaryCategory: "Electronics",
subCategory1: "Audio",
subCategory2: "Headphones"
}
}
});
XDM Schema Alignment
For Web SDK implementations, align data layer with XDM:
adobeDataLayer.push({
event: "pageView",
eventInfo: {
eventName: "Page View",
eventType: "web.webpagedetails.pageViews"
},
web: {
webPageDetails: {
name: "Product Detail - Wireless Headphones",
siteSection: "Electronics",
pageViews: { value: 1 }
}
}
});
Traditional Data Layer Format
For AppMeasurement implementations:
var digitalData = {
page: {
pageName: "example:electronics:headphones:pdp",
pageType: "product",
siteSection: "electronics",
channel: "web"
},
user: {
loginStatus: "logged_in",
customerID: "user_12345",
customerType: "premium"
},
cart: {
cartID: "cart_98765",
items: [],
total: 0
}
};
Required Fields by Page Type
All Pages
| Field | Maps To | Description | Example |
|---|---|---|---|
pageName |
s.pageName | Unique page identifier | example:home |
pageType |
prop/eVar | Page classification | home, product, checkout |
siteSection |
s.channel | Primary content area | electronics, support |
server |
s.server | Server/hostname | www.example.com |
language |
prop | Page language | en-US |
loginStatus |
prop/eVar | User authentication state | logged_in, guest |
Product Detail Pages
adobeDataLayer.push({
event: "productView",
product: {
productInfo: {
productID: "SKU-12345",
productName: "Wireless Headphones",
sku: "WH-BLK-001",
brand: "AudioTech"
},
category: {
primaryCategory: "Electronics",
subCategory1: "Audio",
subCategory2: "Headphones"
},
price: {
basePrice: 79.99,
salePrice: 69.99,
currency: "USD"
},
availability: "inStock"
}
});
Cart Updates
adobeDataLayer.push({
event: "addToCart",
cart: {
cartID: "cart_98765",
items: [
{
productID: "SKU-12345",
productName: "Wireless Headphones",
quantity: 1,
price: 69.99,
category: "Electronics;Audio;Headphones"
}
],
cartTotal: 69.99,
itemCount: 1
}
});
Checkout Flow
// Begin checkout
adobeDataLayer.push({
event: "checkoutStart",
checkout: {
step: 1,
stepName: "cart_review",
cart: { /* cart object */ }
}
});
// Shipping step
adobeDataLayer.push({
event: "checkoutStep",
checkout: {
step: 2,
stepName: "shipping",
shippingMethod: "ground",
shippingCost: 5.99
}
});
// Payment step
adobeDataLayer.push({
event: "checkoutStep",
checkout: {
step: 3,
stepName: "payment",
paymentMethod: "credit_card"
}
});
Order Confirmation
adobeDataLayer.push({
event: "purchase",
transaction: {
transactionID: "ORD-98765",
revenue: 156.96,
tax: 8.00,
shipping: 5.99,
discount: 10.00,
currency: "USD",
paymentMethod: "credit_card",
items: [
{
productID: "SKU-12345",
productName: "Wireless Headphones",
category: "Electronics;Audio;Headphones",
quantity: 1,
price: 69.99
}
]
}
});
Product String Formatting
Adobe Analytics uses a specific product string format:
Category;Product;Quantity;Price;Events;Merchandising
Building Product Strings
function buildProductString(items) {
return items.map(item => {
const category = item.category || "";
const product = item.productID;
const quantity = item.quantity || 1;
const price = item.price * quantity;
const events = ""; // e.g., "event1=5" for merchandising
const merch = ""; // e.g., "eVar10=promo123"
return [category, product, quantity, price, events, merch]
.join(";")
.replace(/;+$/, ""); // Trim trailing semicolons
}).join(",");
}
// Result: "Electronics;SKU-12345;1;69.99"
Merchandising eVar Binding
For product-level eVars:
// Syntax: Category;Product;Quantity;Price;Events;eVarN=value
var productString = "Electronics;SKU-12345;1;69.99;;eVar10=summer-promo|eVar11=recommended";
eVar and Prop Mapping
Solution Design Reference Alignment
Maintain a mapping table in your Solution Design Reference:
| Data Layer Variable | Adobe Variable | Allocation | Expiration |
|---|---|---|---|
page.pageType |
prop1 | Most Recent | Hit |
page.siteSection |
eVar1 | Most Recent | Visit |
user.customerType |
eVar5 | Most Recent | 90 days |
product.category |
eVar10 | Product | Purchase |
campaign.trackingCode |
eVar50 | Original | 30 days |
Launch Rule Mapping
In Adobe Launch, create data elements:
// Data Element: dl_pageName
return digitalData.page.pageName || "";
// Data Element: dl_customerType
return digitalData.user.customerType || "guest";
Then map in your Analytics extension:
| Field | Set from Data Element |
|---|---|
| s.pageName | %dl_pageName% |
| eVar5 | %dl_customerType% |
Marketing Channel Data
Campaign Tracking
adobeDataLayer.push({
marketing: {
trackingCode: "summer2024_email_product",
source: "email",
medium: "marketing",
campaign: "summer2024",
content: "product_spotlight",
term: ""
}
});
Processing Rule Mapping
Set up Processing Rules to map context data:
| Context Data | Maps To | Rule |
|---|---|---|
a.marketing.trackingCode |
eVar50 | Set Always |
a.marketing.source |
eVar51 | Set If Not Set |
Identity and Privacy
User Identification
adobeDataLayer.push({
user: {
ecid: Visitor.getInstance("ORG_ID").getMarketingCloudVisitorID(),
customerID: "user_12345", // CRM ID
loginStatus: "logged_in",
authState: "authenticated"
}
});
Consent State
adobeDataLayer.push({
privacy: {
consentState: "opted_in",
consentCategories: ["analytics", "personalization"],
consentTimestamp: "2024-01-15T10:30:00Z"
}
});
Conditional Data Based on Consent
function pushUserData() {
var userData = {
loginStatus: digitalData.user.loginStatus
};
if (hasConsent('analytics')) {
userData.customerID = digitalData.user.customerID;
userData.customerType = digitalData.user.customerType;
}
adobeDataLayer.push({ user: userData });
}
Governance and Versioning
Schema Version Tracking
adobeDataLayer.push({
schemaVersion: "2.3.0",
page: { /* ... */ }
});
Solution Design Reference Updates
When changing data layer structure:
- Update SDR with new variable allocations
- Document mapping changes in version history
- Review Launch rules for impacted data elements
- Test in development report suite first
- Communicate to stakeholders before deployment
Change Management
| Step | Action |
|---|---|
| 1 | Propose change in SDR with business justification |
| 2 | Review eVar/prop availability and expiration settings |
| 3 | Update data elements in Launch development environment |
| 4 | Test with QA team using development report suite |
| 5 | Deploy to staging and validate with Assurance |
| 6 | Publish to production with monitoring plan |
Validation and Debugging
Adobe Experience Platform Debugger
- Install the Debugger browser extension
- Navigate to your site
- Open Debugger and select Analytics tab
- Verify variable mappings match SDR
Data Layer Inspection
// View current data layer state
console.log(JSON.stringify(adobeDataLayer, null, 2));
// Monitor pushes in real-time
adobeDataLayer.push = (function(originalPush) {
return function() {
console.log('Data Layer Push:', arguments[0]);
return originalPush.apply(this, arguments);
};
})(adobeDataLayer.push);
Validation Checklist
| Check | Expected Result |
|---|---|
| pageName follows naming convention | Consistent hierarchy separator |
| Product string properly formatted | Category;SKU;Qty;Price syntax |
| eVars match SDR allocation | Correct variable numbers |
| Currency values numeric | No formatting, correct decimal |
| ECID present | 38-character string |
| Consent respected | No PII when opted out |