Criteo Data Layer Setup | Blue Frog Docs

Criteo Data Layer Setup

Configure a comprehensive data layer for Criteo tracking, including product information, user data, and transaction details for optimal retargeting performance.

A well-structured data layer ensures accurate tracking and enables advanced Criteo features. This guide covers data layer architecture, implementation patterns, and best practices for e-commerce tracking.

Data Layer Overview

A data layer is a JavaScript object that stores structured data about the page, products, users, and interactions. It serves as a single source of truth for all tracking tags.

Benefits of Data Layer

  • Separation of Concerns - Decouples business logic from tracking code
  • Consistency - Single data structure for all marketing tags
  • Maintainability - Easier to update tracking without changing tag code
  • Reliability - Data available before tags load
  • Flexibility - Supports multiple analytics platforms

Data Layer Architecture

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  // Page Information
  pageType: 'product',          // home, category, product, cart, checkout, confirmation
  pagePath: '/products/headphones',
  pageTitle: 'Wireless Headphones - Your Store',

  // Product Information
  product: {
    id: 'PROD_123',
    name: 'Wireless Headphones',
    price: 99.99,
    salePrice: 79.99,
    currency: 'USD',
    brand: 'AudioBrand',
    category: 'Electronics/Audio/Headphones',
    availability: 'in stock',
    imageUrl: 'https://example.com/images/headphones.jpg'
  },

  // User Information
  user: {
    id: 'USER_456',
    email: 'user@example.com',
    isLoggedIn: true,
    isNewCustomer: false
  },

  // Cart Information
  cart: {
    items: [],
    itemCount: 0,
    total: 0
  },

  // Transaction Information
  transaction: {
    id: '',
    revenue: 0,
    tax: 0,
    shipping: 0,
    items: []
  }
});

Page-Specific Data Layers

Homepage Data Layer

// Homepage
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: 'home',
  pagePath: '/',
  pageTitle: 'Homepage - Your Store',

  // Featured products (optional)
  featuredProducts: [
    { id: 'PROD_123', name: 'Wireless Headphones', price: 99.99 },
    { id: 'PROD_456', name: 'Bluetooth Speaker', price: 49.99 },
    { id: 'PROD_789', name: 'Smart Watch', price: 199.99 }
  ],

  // User info if logged in
  user: {
    id: getUserId(),
    email: getUserEmail(),
    isLoggedIn: isUserLoggedIn()
  }
});

Product Page Data Layer

// Product Detail Page
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: 'product',
  pagePath: window.location.pathname,
  pageTitle: document.title,

  product: {
    id: 'PROD_123',
    sku: 'WH-1000XM4',
    name: 'Wireless Noise-Canceling Headphones',
    description: 'Premium wireless headphones with active noise cancellation',
    price: 349.99,
    salePrice: 299.99,
    currency: 'USD',
    brand: 'AudioBrand',
    category: 'Electronics/Audio/Headphones',
    subcategory: 'Over-Ear Headphones',
    availability: 'in stock',
    stockLevel: 15,
    imageUrl: 'https://example.com/images/headphones-main.jpg',
    additionalImages: [
      'https://example.com/images/headphones-2.jpg',
      'https://example.com/images/headphones-3.jpg'
    ],

    // Product attributes
    attributes: {
      color: 'Black',
      size: 'Standard',
      material: 'Plastic/Leather'
    },

    // Variant information
    variant: {
      id: 'PROD_123_BLACK',
      color: 'Black',
      sku: 'WH-1000XM4-BLK'
    },

    // Additional metadata
    rating: 4.5,
    reviewCount: 1247,
    condition: 'new',
    gtin: '1234567890123',
    mpn: 'WH-1000XM4'
  },

  user: {
    id: getUserId(),
    email: getUserEmail(),
    isLoggedIn: isUserLoggedIn()
  }
});

Category Page Data Layer

// Category/Listing Page
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: 'category',
  pagePath: '/category/headphones',
  pageTitle: 'Headphones - Your Store',

  category: {
    id: 'CAT_HEADPHONES',
    name: 'Headphones',
    path: 'Electronics/Audio/Headphones',
    productCount: 45
  },

  // Visible products on page
  products: [
    {
      id: 'PROD_123',
      name: 'Wireless Headphones',
      price: 99.99,
      brand: 'AudioBrand',
      position: 1
    },
    {
      id: 'PROD_456',
      name: 'Gaming Headset',
      price: 79.99,
      brand: 'GameAudio',
      position: 2
    },
    {
      id: 'PROD_789',
      name: 'Studio Monitor Headphones',
      price: 149.99,
      brand: 'ProAudio',
      position: 3
    }
  ],

  // Filters applied
  filters: {
    priceRange: '50-150',
    brand: ['AudioBrand', 'GameAudio'],
    features: ['wireless', 'noise-canceling']
  },

  user: {
    id: getUserId(),
    email: getUserEmail(),
    isLoggedIn: isUserLoggedIn()
  }
});

Shopping Cart Data Layer

// Cart Page
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: 'cart',
  pagePath: '/cart',
  pageTitle: 'Shopping Cart - Your Store',

  cart: {
    items: [
      {
        id: 'PROD_123',
        name: 'Wireless Headphones',
        sku: 'WH-1000XM4',
        price: 99.99,
        quantity: 1,
        brand: 'AudioBrand',
        category: 'Electronics/Audio/Headphones',
        variant: 'Black',
        position: 0
      },
      {
        id: 'PROD_456',
        name: 'Bluetooth Speaker',
        sku: 'SPK-200',
        price: 49.99,
        quantity: 2,
        brand: 'AudioBrand',
        category: 'Electronics/Audio/Speakers',
        variant: 'Blue',
        position: 1
      }
    ],
    itemCount: 3,
    subtotal: 199.97,
    tax: 0,
    shipping: 0,
    discount: 20.00,
    couponCode: 'SAVE20',
    total: 179.97,
    currency: 'USD'
  },

  user: {
    id: getUserId(),
    email: getUserEmail(),
    isLoggedIn: isUserLoggedIn()
  }
});

Checkout Page Data Layer

// Checkout Page
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: 'checkout',
  pagePath: '/checkout',
  pageTitle: 'Checkout - Your Store',

  checkoutStep: 1, // 1=shipping, 2=payment, 3=review

  cart: {
    items: [
      {
        id: 'PROD_123',
        name: 'Wireless Headphones',
        price: 99.99,
        quantity: 1
      },
      {
        id: 'PROD_456',
        name: 'Bluetooth Speaker',
        price: 49.99,
        quantity: 2
      }
    ],
    subtotal: 199.97,
    tax: 16.00,
    shipping: 10.00,
    discount: 20.00,
    total: 205.97,
    currency: 'USD'
  },

  user: {
    id: getUserId(),
    email: getUserEmail(),
    isLoggedIn: isUserLoggedIn(),
    shippingAddress: {
      country: 'US',
      state: 'CA',
      city: 'San Francisco',
      zipCode: '94102'
    }
  }
});

Order Confirmation Data Layer

// Order Confirmation Page
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: 'confirmation',
  pagePath: '/order/confirmation',
  pageTitle: 'Order Confirmation - Your Store',

  transaction: {
    id: 'ORDER_12345',
    affiliation: 'Online Store',
    revenue: 205.97,
    tax: 16.00,
    shipping: 10.00,
    discount: 20.00,
    coupon: 'SAVE20',
    currency: 'USD',

    items: [
      {
        id: 'PROD_123',
        name: 'Wireless Headphones',
        sku: 'WH-1000XM4',
        price: 99.99,
        quantity: 1,
        brand: 'AudioBrand',
        category: 'Electronics/Audio/Headphones',
        variant: 'Black'
      },
      {
        id: 'PROD_456',
        name: 'Bluetooth Speaker',
        sku: 'SPK-200',
        price: 49.99,
        quantity: 2,
        brand: 'AudioBrand',
        category: 'Electronics/Audio/Speakers',
        variant: 'Blue'
      }
    ]
  },

  user: {
    id: 'USER_456',
    email: 'user@example.com',
    isLoggedIn: true,
    isNewCustomer: true // First purchase
  }
});

Mapping Data Layer to Criteo Events

Homepage Mapping

// Read from data layer
const pageData = window.dataLayer[0];

// Map to Criteo event
window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
  { event: "setAccount", account: 12345 },
  { event: "setSiteType", type: deviceType }
);

if (pageData.user.email) {
  window.criteo_q.push({
    event: "setEmail",
    email: pageData.user.email
  });
}

if (pageData.pageType === 'home') {
  window.criteo_q.push({ event: "viewHome" });
}

Product Page Mapping

const pageData = window.dataLayer[0];

window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
  { event: "setAccount", account: 12345 },
  { event: "setSiteType", type: deviceType }
);

if (pageData.user.email) {
  window.criteo_q.push({ event: "setEmail", email: pageData.user.email });
}

if (pageData.pageType === 'product' && pageData.product) {
  window.criteo_q.push({
    event: "viewItem",
    item: pageData.product.id
  });
}

Cart Page Mapping

const pageData = window.dataLayer[0];

window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
  { event: "setAccount", account: 12345 },
  { event: "setSiteType", type: deviceType }
);

if (pageData.user.email) {
  window.criteo_q.push({ event: "setEmail", email: pageData.user.email });
}

if (pageData.pageType === 'cart' && pageData.cart.items.length > 0) {
  const cartItems = pageData.cart.items.map(item => ({
    id: item.id,
    price: item.price,
    quantity: item.quantity
  }));

  window.criteo_q.push({
    event: "viewBasket",
    item: cartItems
  });
}

Transaction Mapping

const pageData = window.dataLayer[0];

window.criteo_q = window.criteo_q || [];
window.criteo_q.push(
  { event: "setAccount", account: 12345 },
  { event: "setSiteType", type: deviceType }
);

if (pageData.user.email) {
  window.criteo_q.push({ event: "setEmail", email: pageData.user.email });
}

if (pageData.pageType === 'confirmation' && pageData.transaction) {
  const transactionItems = pageData.transaction.items.map(item => ({
    id: item.id,
    price: item.price,
    quantity: item.quantity
  }));

  window.criteo_q.push({
    event: "trackTransaction",
    id: pageData.transaction.id,
    item: transactionItems,
    new_customer: pageData.user.isNewCustomer ? 1 : 0
  });
}

Generic Data Layer to Criteo Mapper

Create a reusable function to map any data layer to Criteo:

// criteo-mapper.js
function mapDataLayerToCriteo() {
  // Get data layer
  const pageData = window.dataLayer?.[0];
  if (!pageData) {
    console.warn('Data layer not found');
    return;
  }

  // Initialize Criteo queue
  window.criteo_q = window.criteo_q || [];

  // Device detection
  const deviceType = /iPad/.test(navigator.userAgent) ? "t" :
                     /Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Silk/.test(navigator.userAgent) ? "m" : "d";

  // Core events (required on all pages)
  window.criteo_q.push(
    { event: "setAccount", account: window.CRITEO_ACCOUNT_ID },
    { event: "setSiteType", type: deviceType }
  );

  // User email (if available)
  if (pageData.user?.email) {
    window.criteo_q.push({
      event: "setEmail",
      email: pageData.user.email
    });
  }

  // Page-specific events
  switch (pageData.pageType) {
    case 'home':
      window.criteo_q.push({ event: "viewHome" });
      break;

    case 'product':
      if (pageData.product?.id) {
        window.criteo_q.push({
          event: "viewItem",
          item: pageData.product.id
        });
      }
      break;

    case 'category':
      if (pageData.products?.length > 0) {
        const productIds = pageData.products.slice(0, 3).map(p => p.id);
        window.criteo_q.push({
          event: "viewList",
          item: productIds
        });
      }
      break;

    case 'cart':
      if (pageData.cart?.items?.length > 0) {
        const cartItems = pageData.cart.items.map(item => ({
          id: item.id,
          price: item.price,
          quantity: item.quantity
        }));
        window.criteo_q.push({
          event: "viewBasket",
          item: cartItems
        });
      }
      break;

    case 'confirmation':
      if (pageData.transaction?.id) {
        const transactionItems = pageData.transaction.items.map(item => ({
          id: item.id,
          price: item.price,
          quantity: item.quantity
        }));

        window.criteo_q.push({
          event: "trackTransaction",
          id: pageData.transaction.id,
          item: transactionItems,
          new_customer: pageData.user?.isNewCustomer ? 1 : 0
        });
      }
      break;

    default:
      console.warn('Unknown page type:', pageData.pageType);
  }
}

// Execute after data layer is ready
if (document.readyState === 'complete') {
  mapDataLayerToCriteo();
} else {
  window.addEventListener('load', mapDataLayerToCriteo);
}

E-commerce Platform Integration

Shopify Data Layer

<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: '{{ template.name }}',

  {% if template.name == 'product' %}
  product: {
    id: '{{ product.id }}',
    name: '{{ product.title | escape }}',
    price: {{ product.price | money_without_currency }},
    {% if product.compare_at_price > product.price %}
    salePrice: {{ product.price | money_without_currency }},
    originalPrice: {{ product.compare_at_price | money_without_currency }},
    {% endif %}
    brand: '{{ product.vendor | escape }}',
    category: '{{ product.type | escape }}',
    availability: '{% if product.available %}in stock{% else %}out of stock{% endif %}',
    imageUrl: 'https:{{ product.featured_image | img_url: "large" }}'
  },
  {% endif %}

  {% if template.name == 'cart' %}
  cart: {
    items: [
      {% for item in cart.items %}
      {
        id: '{{ item.product_id }}',
        name: '{{ item.title | escape }}',
        price: {{ item.final_price | money_without_currency }},
        quantity: {{ item.quantity }}
      }{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ],
    total: {{ cart.total_price | money_without_currency }}
  },
  {% endif %}

  {% if customer %}
  user: {
    id: '{{ customer.id }}',
    email: '{{ customer.email }}',
    isLoggedIn: true
  }
  {% endif %}
});
</script>

WooCommerce Data Layer

<!-- In functions.php or custom plugin -->
<?php
function add_criteo_data_layer() {
  ?>
  <script>
  window.dataLayer = window.dataLayer || [];
  window.dataLayer.push({
    pageType: '<?php echo get_page_type(); ?>',

    <?php if (is_product()) : ?>
      <?php global $product; ?>
      product: {
        id: '<?php echo $product->get_id(); ?>',
        name: '<?php echo esc_js($product->get_name()); ?>',
        price: <?php echo $product->get_price(); ?>,
        brand: '<?php echo esc_js(get_product_brand($product)); ?>',
        category: '<?php echo esc_js(get_product_category($product)); ?>',
        availability: '<?php echo $product->is_in_stock() ? "in stock" : "out of stock"; ?>'
      },
    <?php endif; ?>

    <?php if (is_cart()) : ?>
      cart: {
        items: [
          <?php
          foreach (WC()->cart->get_cart() as $cart_item) {
            $product = $cart_item['data'];
            echo '{';
            echo 'id: "' . $product->get_id() . '",';
            echo 'name: "' . esc_js($product->get_name()) . '",';
            echo 'price: ' . $product->get_price() . ',';
            echo 'quantity: ' . $cart_item['quantity'];
            echo '},';
          }
          ?>
        ],
        total: <?php echo WC()->cart->get_total(''); ?>
      },
    <?php endif; ?>

    <?php if (is_user_logged_in()) : ?>
      <?php $user = wp_get_current_user(); ?>
      user: {
        id: '<?php echo $user->ID; ?>',
        email: '<?php echo $user->user_email; ?>',
        isLoggedIn: true
      }
    <?php endif; ?>
  });
  </script>
  <?php
}
add_action('wp_head', 'add_criteo_data_layer');
?>

Magento Data Layer

<!-- In template file -->
<?php
$dataLayer = [
    'pageType' => $this->getPageType(),
];

if ($this->getPageType() === 'product') {
    $product = $this->getProduct();
    $dataLayer['product'] = [
        'id' => $product->getId(),
        'name' => $product->getName(),
        'price' => $product->getFinalPrice(),
        'brand' => $product->getAttributeText('brand'),
        'category' => $this->getCategoryPath($product),
        'availability' => $product->isAvailable() ? 'in stock' : 'out of stock'
    ];
}
?>
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push(<?php echo json_encode($dataLayer); ?>);
</script>

Dynamic Data Layer Updates

For single-page applications or AJAX interactions:

// Add item to cart (AJAX)
function addToCartAndUpdateDataLayer(productId, quantity) {
  // Add to cart via API
  fetch('/api/cart/add', {
    method: 'POST',
    body: JSON.stringify({ productId, quantity })
  })
  .then(response => response.json())
  .then(cart => {
    // Update data layer
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push({
      event: 'addToCart',
      cart: {
        items: cart.items,
        total: cart.total
      }
    });

    // Fire Criteo event
    window.criteo_q = window.criteo_q || [];
    window.criteo_q.push({
      event: "addToCart",
      product: {
        id: productId,
        quantity: quantity
      }
    });
  });
}

// Remove item from cart
function removeFromCartAndUpdateDataLayer(productId) {
  fetch('/api/cart/remove', {
    method: 'POST',
    body: JSON.stringify({ productId })
  })
  .then(response => response.json())
  .then(cart => {
    // Update data layer
    window.dataLayer.push({
      event: 'removeFromCart',
      cart: cart
    });
  });
}

Testing and Validation

Verify Data Layer

// Check data layer in console
console.log('Data Layer:', window.dataLayer);

// Validate structure
function validateDataLayer() {
  const data = window.dataLayer?.[0];

  if (!data) {
    console.error('Data layer not found');
    return false;
  }

  const required = ['pageType'];
  const missing = required.filter(field => !data[field]);

  if (missing.length > 0) {
    console.error('Missing required fields:', missing);
    return false;
  }

  console.log('✓ Data layer valid');
  return true;
}

validateDataLayer();

Data Layer Inspector

// Create visual inspector
function inspectDataLayer() {
  const data = window.dataLayer?.[0];
  console.group('Data Layer Inspector');
  console.log('Page Type:', data?.pageType);
  console.log('Product:', data?.product);
  console.log('Cart:', data?.cart);
  console.log('User:', data?.user);
  console.log('Transaction:', data?.transaction);
  console.groupEnd();
}

// Run on page load
inspectDataLayer();

Best Practices

  1. Initialize Early - Load data layer before any tracking tags
  2. Single Source of Truth - Use data layer for all marketing tags
  3. Consistent Format - Maintain same structure across all pages
  4. Privacy First - Don't include sensitive data in plain text
  5. Validate Data - Implement validation before pushing to data layer
  6. Document Schema - Maintain documentation of data layer structure
  7. Version Control - Track changes to data layer schema

Next Steps

// SYS.FOOTER