Cross-domain tracking enables Criteo to follow users across different domains within your business ecosystem, maintaining continuous user sessions for more effective retargeting.
What is Cross-Domain Tracking?
Cross-domain tracking allows Criteo to recognize the same user across multiple domains or subdomains, ensuring:
- Continuous user journey tracking
- Accurate attribution across domains
- Unified audience building
- Better retargeting performance
- Complete conversion funnel visibility
Common Use Cases
Multiple Brand Domains:
- Main site:
store.com - Clearance site:
outlet.store.com - Mobile site:
m.store.com
Separate Checkout Domains:
- Shopping:
shop.example.com - Checkout:
secure-checkout.example.com
International Sites:
- US site:
example.com - UK site:
example.co.uk - EU site:
example.eu
Partner Domains:
- Main store:
brandstore.com - Marketplace:
marketplace.partner.com
How Criteo Cross-Domain Tracking Works
Criteo uses cookies and URL parameters to maintain user identity across domains:
- First-Party Cookies - Stored on each domain
- User Sync - Criteo's cross-domain sync mechanism
- URL Parameter Passing - Optional for enhanced tracking
- Device Graph - Criteo's cross-device identification
Automatic Cross-Domain Support
Criteo OneTag automatically supports cross-domain tracking through:
- Cookie synchronization frames
- User matching algorithms
- Device fingerprinting
- Cross-device graph matching
Basic Cross-Domain Setup
Same Organization Domains
For domains you control, Criteo automatically handles cross-domain tracking when using the same account ID:
<!-- On domain1.com -->
<script type="text/javascript" src="//dynamic.criteo.com/js/ld/ld.js" async="true"></script>
<script type="text/javascript">
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
{ event: "setAccount", account: 12345 }, // Same account ID
{ event: "setSiteType", type: deviceType },
{ event: "viewHome" }
);
</script>
<!-- On domain2.com -->
<script type="text/javascript" src="//dynamic.criteo.com/js/ld/ld.js" async="true"></script>
<script type="text/javascript">
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
{ event: "setAccount", account: 12345 }, // Same account ID
{ event: "setSiteType", type: deviceType },
{ event: "viewHome" }
);
</script>
Key Requirements:
- Use the same Criteo account ID on all domains
- Deploy OneTag consistently across all domains
- Ensure cookies are not blocked between domains
Enhanced Cross-Domain Tracking
Using setSiteId
For better cross-domain attribution, use site identifiers:
// Main store domain
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType },
{ event: "setSiteId", id: "main-store" } // Unique site identifier
);
// Outlet domain
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType },
{ event: "setSiteId", id: "outlet-store" } // Different site identifier
);
// Mobile domain
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType },
{ event: "setSiteId", id: "mobile-store" } // Mobile site identifier
);
Benefits:
- Track performance by domain/subdomain
- Separate reporting per site
- Maintain unified user tracking
- Domain-specific optimization
Subdomain Tracking
Automatic Subdomain Tracking
Criteo automatically tracks across subdomains of the same root domain:
example.com ← Root domain
www.example.com ← Automatically tracked
shop.example.com ← Automatically tracked
blog.example.com ← Automatically tracked
m.example.com ← Automatically tracked
Implementation
// Same OneTag code on all subdomains
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType }
);
// Optionally identify subdomain
const subdomain = window.location.hostname.split('.')[0];
window.criteo_q.push({
event: "setSiteId",
id: subdomain
});
Multiple Domain Configuration
Linking Domains in Criteo Dashboard
- Log in to Criteo Management Center
- Navigate to Settings > Domain Configuration
- Add all domains you want to track:
domain1.comdomain2.comcheckout.partner.com
- Save configuration
Verify Domain Linking
// Test cross-domain user recognition
function testCrossDomainTracking() {
// On domain1.com
sessionStorage.setItem('criteo_test_timestamp', Date.now());
// Navigate to domain2.com
// Check if same user is recognized by Criteo
// (Visible in Criteo reporting)
}
URL Parameter Passing
For enhanced cross-domain tracking, pass user identifiers in URLs when linking between domains.
Automatic Link Decoration
// Automatically append Criteo parameters to cross-domain links
function decorateCrossDomainLinks() {
const crossDomainHosts = [
'store.example.com',
'checkout.example.com',
'partner-site.com'
];
document.querySelectorAll('a').forEach(link => {
try {
const url = new URL(link.href);
// Check if link is to a cross-domain
if (crossDomainHosts.includes(url.hostname) &&
url.hostname !== window.location.hostname) {
// Add Criteo tracking parameter
url.searchParams.set('criteo_ref', getCriteoUserId());
link.href = url.toString();
}
} catch (e) {
// Invalid URL, skip
}
});
}
// Run on page load
if (document.readyState === 'complete') {
decorateCrossDomainLinks();
} else {
window.addEventListener('load', decorateCrossDomainLinks);
}
// Helper to get Criteo user ID (from cookie or generate)
function getCriteoUserId() {
// Simplified example - Criteo handles this automatically
return document.cookie
.split('; ')
.find(row => row.startsWith('cto_bundle='))
?.split('=')[1] || '';
}
Manual Link Decoration
<!-- Link from main site to checkout domain -->
<a href="https://checkout.example.com/cart?product=123&criteo_ref=USER_ID">
Proceed to Checkout
</a>
User Identification Across Domains
Email-Based Matching
Use consistent email hashing across all domains:
// Shared email hashing function (use on all domains)
async function hashEmailForCriteo(email) {
const normalized = email.toLowerCase().trim();
const msgBuffer = new TextEncoder().encode(normalized);
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('');
}
// On domain1.com
const userEmail = 'user@example.com';
const hashedEmail = await hashEmailForCriteo(userEmail);
window.criteo_q.push({
event: "setHashedEmail",
email: hashedEmail
});
// On domain2.com (same user)
const userEmail = 'user@example.com';
const hashedEmail = await hashEmailForCriteo(userEmail);
window.criteo_q.push({
event: "setHashedEmail",
email: hashedEmail
});
Customer ID Matching
// Use consistent customer IDs across domains
const customerId = getCustomerIdFromSession(); // e.g., "CUST_12345"
// On all domains
window.criteo_q.push({
event: "setCustomerId",
id: customerId
});
Cross-Domain Shopping Flows
Multi-Domain Checkout
Example: Shopping on shop.example.com, checkout on secure.payment.com
Shop Domain (shop.example.com):
// Product view
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType },
{ event: "viewItem", item: "PROD_123" }
);
// Add to cart
window.criteo_q.push({
event: "viewBasket",
item: [
{ id: "PROD_123", price: 99.99, quantity: 1 }
]
});
// Link to checkout with user context
function proceedToCheckout() {
const cartData = encodeURIComponent(JSON.stringify(getCartItems()));
const checkoutUrl = `https://secure.payment.com/checkout?cart=${cartData}`;
window.location.href = checkoutUrl;
}
Checkout Domain (secure.payment.com):
// On checkout page
window.criteo_q.push(
{ event: "setAccount", account: 12345 }, // Same account ID
{ event: "setSiteType", type: deviceType }
);
// Get cart from URL or session
const cartItems = getCartItemsFromUrl();
window.criteo_q.push({
event: "viewBasket",
item: cartItems
});
// On order confirmation
window.criteo_q.push({
event: "trackTransaction",
id: "ORDER_12345",
item: cartItems
});
Third-Party Marketplace
Example: Your store integrates with external marketplace
Your Store (yourstore.com):
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType },
{ event: "viewItem", item: "PROD_123" }
);
// Link to marketplace with product ID
const marketplaceUrl = `https://marketplace.partner.com/buy?product=PROD_123&merchant=yourstore`;
Marketplace (marketplace.partner.com):
// Marketplace implements Criteo with your account ID
window.criteo_q.push(
{ event: "setAccount", account: 12345 }, // Your account ID
{ event: "setSiteType", type: deviceType },
{ event: "trackTransaction", id: "ORDER_12345", item: [...] }
);
International Multi-Domain Setup
Regional Sites
Track users across country-specific domains:
// US site (example.com)
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType },
{ event: "setSiteId", id: "us-site" },
{ event: "viewHome" }
);
// UK site (example.co.uk)
window.criteo_q.push(
{ event: "setAccount", account: 12345 }, // Same account
{ event: "setSiteType", type: deviceType },
{ event: "setSiteId", id: "uk-site" },
{ event: "viewHome" }
);
// EU site (example.eu)
window.criteo_q.push(
{ event: "setAccount", account: 12345 }, // Same account
{ event: "setSiteType", type: deviceType },
{ event: "setSiteId", id: "eu-site" },
{ event: "viewHome" }
);
Regional Compliance
Handle privacy regulations across regions:
// Check user's region and consent status
function loadCriteoWithConsent() {
const userRegion = getUserRegion(); // e.g., 'EU', 'US', 'UK'
const hasConsent = checkMarketingConsent(userRegion);
if (hasConsent) {
// Load Criteo OneTag
const script = document.createElement('script');
script.src = '//dynamic.criteo.com/js/ld/ld.js';
script.async = true;
document.head.appendChild(script);
// Initialize
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: deviceType },
{ event: "setSiteId", id: `${userRegion.toLowerCase()}-site` }
);
}
}
Mobile App and Web Integration
App-to-Web Tracking
Track users moving from mobile app to mobile web:
Mobile App:
// In app's webview or deep link
const webUrl = 'https://m.example.com/product/123?app_user_id=' +
encodeURIComponent(appUserId);
// Open in webview or external browser
window.open(webUrl);
Mobile Web:
// On m.example.com
const urlParams = new URLSearchParams(window.location.search);
const appUserId = urlParams.get('app_user_id');
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
{ event: "setAccount", account: 12345 },
{ event: "setSiteType", type: "m" }, // Mobile
{ event: "setCustomerId", id: appUserId } // Link app user
);
Testing Cross-Domain Tracking
Manual Testing
- Clear Cookies - Start with clean slate
- Visit Domain 1 - Browse products, add to cart
- Navigate to Domain 2 - Complete purchase
- Verify in Criteo Dashboard - Check if journey is tracked as single user
Automated Testing
// Test cross-domain user persistence
async function testCrossDomainTracking() {
const testId = `test_${Date.now()}`;
// Set test identifier on domain 1
window.criteo_q.push({
event: "setCustomerId",
id: testId
});
// Simulate navigation to domain 2
// (In real test, open domain 2 in same browser)
// On domain 2, check if same user ID is recognized
setTimeout(() => {
// Check Criteo's user sync
console.log('Test ID:', testId);
console.log('Criteo cookies:', document.cookie);
}, 1000);
}
Verification Script
// Run on each domain to verify configuration
function verifyCrossDomainSetup() {
console.group('Criteo Cross-Domain Configuration');
// Check account ID
const accountEvent = window.criteo_q.find(e => e.event === 'setAccount');
console.log('✓ Account ID:', accountEvent?.account);
// Check site ID
const siteIdEvent = window.criteo_q.find(e => e.event === 'setSiteId');
console.log('✓ Site ID:', siteIdEvent?.id || 'Not set');
// Check domain
console.log('✓ Current domain:', window.location.hostname);
// Check cookies
const cteoCookies = document.cookie
.split('; ')
.filter(c => c.startsWith('cto_'));
console.log('✓ Criteo cookies:', cteoCookies.length);
console.groupEnd();
}
verifyCrossDomainSetup();
Common Issues and Solutions
Issue: Users Not Tracked Across Domains
Causes:
- Different account IDs on different domains
- Cookie blocking between domains
- Missing OneTag on some domains
Solutions:
// Verify same account ID everywhere
const accountId = 12345; // Use constant
// On all domains
window.criteo_q.push({
event: "setAccount",
account: accountId
});
// Check cookie access
if (!navigator.cookieEnabled) {
console.error('Cookies are disabled');
}
Issue: Inconsistent User Identification
Causes:
- Different email formats
- Inconsistent customer IDs
- Missing user identification
Solutions:
// Standardize email format
function normalizeEmail(email) {
return email.toLowerCase().trim();
}
// Use consistent customer ID format
function getStandardCustomerId(id) {
return `CUST_${id.toString().padStart(8, '0')}`;
}
// Always set user identification
const userId = getStandardCustomerId(getUserId());
const userEmail = normalizeEmail(getUserEmail());
window.criteo_q.push(
{ event: "setCustomerId", id: userId },
{ event: "setHashedEmail", email: await hashEmail(userEmail) }
);
Issue: Third-Party Cookie Blocking
Impact:
- Safari ITP (Intelligent Tracking Prevention)
- Firefox Enhanced Tracking Protection
- Chrome Privacy Sandbox
Solutions:
// Use first-party cookies and server-side tracking
// Implement user identification via login
if (isUserLoggedIn()) {
window.criteo_q.push({
event: "setCustomerId",
id: getAuthenticatedUserId()
});
}
// Consider server-side implementation for better reliability
Best Practices
- Consistent Account ID - Use the same Criteo account across all domains
- User Identification - Implement email/customer ID tracking
- Domain Registration - Register all domains in Criteo Management Center
- Testing - Test cross-domain flows before launch
- Cookie Consent - Respect privacy regulations across all domains
- Documentation - Document cross-domain setup for team reference
- Monitoring - Monitor cross-domain tracking performance regularly
Advanced: Server-Side Cross-Domain Tracking
For enhanced reliability, implement server-side user matching:
// Server-side API call
async function trackCrossDomainEvent(userId, event) {
const response = await fetch('/api/criteo/track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userId: userId,
event: event,
domain: window.location.hostname
})
});
return response.json();
}
// Server forwards to Criteo API with consistent user ID
Next Steps
- Server-Side vs Client-Side - Choose implementation approach
- Event Tracking - Implement events across domains
- Troubleshooting - Resolve cross-domain issues