Criteo Cross-Domain Tracking | Blue Frog Docs

Criteo Cross-Domain Tracking

Implement cross-domain tracking for Criteo to maintain user sessions and retargeting across multiple domains and subdomains.

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:

  1. First-Party Cookies - Stored on each domain
  2. User Sync - Criteo's cross-domain sync mechanism
  3. URL Parameter Passing - Optional for enhanced tracking
  4. 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

  1. Log in to Criteo Management Center
  2. Navigate to Settings > Domain Configuration
  3. Add all domains you want to track:
    • domain1.com
    • domain2.com
    • checkout.partner.com
  4. 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.

// 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] || '';
}
<!-- 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

  1. Clear Cookies - Start with clean slate
  2. Visit Domain 1 - Browse products, add to cart
  3. Navigate to Domain 2 - Complete purchase
  4. 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) }
);

Impact:

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

  1. Consistent Account ID - Use the same Criteo account across all domains
  2. User Identification - Implement email/customer ID tracking
  3. Domain Registration - Register all domains in Criteo Management Center
  4. Testing - Test cross-domain flows before launch
  5. Cookie Consent - Respect privacy regulations across all domains
  6. Documentation - Document cross-domain setup for team reference
  7. 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

// SYS.FOOTER