Criteo Event Tracking | Blue Frog Docs

Criteo Event Tracking

Complete guide to implementing Criteo event tracking for product views, shopping cart interactions, conversions, and custom events.

Event tracking is essential for Criteo's retargeting and optimization algorithms. This guide covers all Criteo OneTag events with implementation examples and best practices.

Event Types Overview

Criteo uses different events to track user behavior throughout the customer journey:

Event Purpose Required Page Type
viewHome Track homepage visits Yes Homepage
viewItem Track product views Yes Product pages
viewList Track category browsing Recommended Category/listing pages
viewBasket Track cart contents Recommended Cart page
trackTransaction Track purchases Yes Order confirmation
viewSearch Track search queries Optional Search results

Core Account Setup Events

These events must be included on every page before any other events.

setAccount

Required first event that identifies your Criteo account:

window.criteo_q.push({
  event: "setAccount",
  account: 12345 // Replace with your account ID
});

Important:

  • Must be the first event in the queue
  • Account ID must be a number, not a string
  • Same account ID across all pages

setSiteType

Identifies the device type for proper ad targeting:

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

window.criteo_q.push({
  event: "setSiteType",
  type: deviceType
});

Device Type Values:

  • d = Desktop
  • m = Mobile
  • t = Tablet

Enhanced Device Detection

For better accuracy:

function getCriteoDeviceType() {
  const ua = navigator.userAgent.toLowerCase();
  const width = window.innerWidth || document.documentElement.clientWidth;

  // Tablet detection
  if (/(ipad|tablet|(android(?!.*mobile)))/.test(ua) ||
      (width >= 768 && width <= 1024)) {
    return 't';
  }

  // Mobile detection
  if (/(mobi|iphone|ipod|android.*mobile|blackberry|opera mini)/.test(ua) ||
      width < 768) {
    return 'm';
  }

  // Desktop
  return 'd';
}

window.criteo_q.push({
  event: "setSiteType",
  type: getCriteoDeviceType()
});

User Identification Events

setEmail

Capture user email for enhanced retargeting:

// Plain email (Criteo will hash it)
window.criteo_q.push({
  event: "setEmail",
  email: "user@example.com",
  hash_method: "sha256" // Optional: specify hash method
});

setHashedEmail

Send pre-hashed emails for privacy:

// Hash email client-side
async function hashEmail(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('');
}

// Send hashed email
const userEmail = 'User@Example.com';
const hashedEmail = await hashEmail(userEmail);

window.criteo_q.push({
  event: "setHashedEmail",
  email: hashedEmail
});

Best Practices:

  • Always normalize emails (lowercase, trim whitespace)
  • Hash on server-side when possible
  • Only send for logged-in users
  • Respect user privacy preferences

setCustomerId

Link to your internal customer ID:

window.criteo_q.push({
  event: "setCustomerId",
  id: "CUST_12345"
});

Homepage Event

viewHome

Track visits to your homepage:

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

Complete Homepage Example:

<!DOCTYPE html>
<html>
<head>
  <title>Your Store - Homepage</title>
</head>
<body>
  <!-- Homepage content -->

  <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 || [];
    var deviceType = /iPad/.test(navigator.userAgent) ? "t" :
                     /Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Silk/.test(navigator.userAgent) ? "m" : "d";

    window.criteo_q.push(
      { event: "setAccount", account: 12345 },
      { event: "setSiteType", type: deviceType },
      { event: "viewHome" }
    );
  </script>
</body>
</html>

Product View Event

viewItem

Track when users view a single product:

window.criteo_q.push({
  event: "viewItem",
  item: "PROD_123" // Product ID matching your product feed
});

Product Page Example:

<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 || [];
  var deviceType = /iPad/.test(navigator.userAgent) ? "t" :
                   /Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Silk/.test(navigator.userAgent) ? "m" : "d";

  // Get product ID from page
  var productId = document.querySelector('[data-product-id]').dataset.productId;

  window.criteo_q.push(
    { event: "setAccount", account: 12345 },
    { event: "setSiteType", type: deviceType },
    { event: "viewItem", item: productId }
  );
</script>

Dynamic Implementation:

// Extract product ID from URL
function getProductIdFromUrl() {
  const pathParts = window.location.pathname.split('/');
  return pathParts[pathParts.indexOf('product') + 1] ||
         new URLSearchParams(window.location.search).get('id');
}

// Or from data layer
function getProductIdFromDataLayer() {
  return window.dataLayer?.[0]?.productId;
}

// Or from page content
function getProductIdFromPage() {
  const skuElement = document.querySelector('[itemprop="sku"]');
  const dataElement = document.querySelector('[data-product-id]');
  return skuElement?.content || dataElement?.dataset.productId;
}

const productId = getProductIdFromDataLayer() ||
                  getProductIdFromPage() ||
                  getProductIdFromUrl();

window.criteo_q.push({
  event: "viewItem",
  item: productId
});

Important:

  • Product ID must exactly match the ID in your product feed
  • Fire only on product detail pages, not on category pages
  • Include variant ID if you have product variants

Category/Listing Event

viewList

Track product listing pages with up to 3 products:

window.criteo_q.push({
  event: "viewList",
  item: ["PROD_123", "PROD_456", "PROD_789"] // Array of up to 3 product IDs
});

Category Page Example:

// Get visible products from category page
function getVisibleProducts(limit = 3) {
  const productElements = document.querySelectorAll('.product-item');
  const productIds = [];

  for (let i = 0; i < Math.min(productElements.length, limit); i++) {
    const productId = productElements[i].dataset.productId;
    if (productId) {
      productIds.push(productId);
    }
  }

  return productIds;
}

window.criteo_q.push({
  event: "viewList",
  item: getVisibleProducts()
});

Search Results Page:

// Track search results
const searchResults = Array.from(
  document.querySelectorAll('.search-result')
).slice(0, 3).map(el => el.dataset.productId);

if (searchResults.length > 0) {
  window.criteo_q.push({
    event: "viewList",
    item: searchResults,
    keywords: document.querySelector('#search-query').value // Optional
  });
}

Shopping Cart Event

viewBasket

Track cart contents with product details:

window.criteo_q.push({
  event: "viewBasket",
  item: [
    { id: "PROD_123", price: 99.99, quantity: 1 },
    { id: "PROD_456", price: 49.99, quantity: 2 }
  ]
});

Complete Cart Event:

// Get cart data from page or API
function getCartItems() {
  const cartItems = [];
  const items = document.querySelectorAll('.cart-item');

  items.forEach(item => {
    cartItems.push({
      id: item.dataset.productId,
      price: parseFloat(item.dataset.price),
      quantity: parseInt(item.dataset.quantity)
    });
  });

  return cartItems;
}

// Fire on cart page
window.criteo_q.push({
  event: "viewBasket",
  item: getCartItems()
});

E-commerce Platform Integration:

// Shopify cart example
{% if template == 'cart' %}
<script>
  window.criteo_q = window.criteo_q || [];
  window.criteo_q.push({
    event: "viewBasket",
    item: [
      {% for item in cart.items %}
      {
        id: "{{ item.product_id }}",
        price: {{ item.final_price | money_without_currency }},
        quantity: {{ item.quantity }}
      }{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ]
  });
</script>
{% endif %}

WooCommerce Example:

<!-- In cart.php template -->
<script>
  window.criteo_q = window.criteo_q || [];
  window.criteo_q.push({
    event: "viewBasket",
    item: [
      <?php
      foreach (WC()->cart->get_cart() as $cart_item) {
        $product = $cart_item['data'];
        echo '{';
        echo 'id: "' . $product->get_id() . '",';
        echo 'price: ' . $product->get_price() . ',';
        echo 'quantity: ' . $cart_item['quantity'];
        echo '},';
      }
      ?>
    ]
  });
</script>

React/SPA Example:

// React component
import { useEffect } from 'react';
import { useCart } from '../hooks/useCart';

export default function CartPage() {
  const { items } = useCart();

  useEffect(() => {
    if (items.length > 0) {
      window.criteo_q = window.criteo_q || [];
      window.criteo_q.push({
        event: "viewBasket",
        item: items.map(item => ({
          id: item.productId,
          price: item.price,
          quantity: item.quantity
        }))
      });
    }
  }, [items]);

  return (
    // Cart UI
  );
}

Purchase/Conversion Event

trackTransaction

Track completed purchases - the most important event for ROI tracking:

window.criteo_q.push({
  event: "trackTransaction",
  id: "ORDER_12345", // Unique order ID
  item: [
    { id: "PROD_123", price: 99.99, quantity: 1 },
    { id: "PROD_456", price: 49.99, quantity: 2 }
  ]
});

Complete Transaction Tracking:

// Order confirmation page
function trackCriteoTransaction() {
  // Prevent duplicate firing
  const transactionId = "ORDER_12345";
  const firedTransactions = JSON.parse(
    sessionStorage.getItem('criteo_transactions') || '[]'
  );

  if (firedTransactions.includes(transactionId)) {
    console.log('Transaction already tracked');
    return;
  }

  // Get order details
  const orderItems = [
    { id: "PROD_123", price: 99.99, quantity: 1 },
    { id: "PROD_456", price: 49.99, quantity: 2 }
  ];

  // Fire transaction event
  window.criteo_q = window.criteo_q || [];
  window.criteo_q.push({
    event: "trackTransaction",
    id: transactionId,
    item: orderItems,
    // Optional: Add new customer flag
    new_customer: 1 // 1 for new customers, 0 for returning
  });

  // Mark as tracked
  firedTransactions.push(transactionId);
  sessionStorage.setItem('criteo_transactions',
    JSON.stringify(firedTransactions));
}

// Execute on page load
if (document.readyState === 'complete') {
  trackCriteoTransaction();
} else {
  window.addEventListener('load', trackCriteoTransaction);
}

Platform-Specific Examples:

Shopify:

{% if first_time_accessed %}
<script>
  window.criteo_q = window.criteo_q || [];
  window.criteo_q.push({
    event: "trackTransaction",
    id: "{{ order.order_number }}",
    item: [
      {% for line_item in order.line_items %}
      {
        id: "{{ line_item.product_id }}",
        price: {{ line_item.final_price | money_without_currency }},
        quantity: {{ line_item.quantity }}
      }{% unless forloop.last %},{% endunless %}
      {% endfor %}
    ],
    new_customer: {% if customer.orders_count == 1 %}1{% else %}0{% endif %}
  });
</script>
{% endif %}

WooCommerce:

<!-- In thankyou.php template -->
<?php
// Prevent duplicate tracking
$order_tracked = get_post_meta($order->get_id(), '_criteo_tracked', true);
if (!$order_tracked) {
  update_post_meta($order->get_id(), '_criteo_tracked', 'yes');
  ?>
  <script>
    window.criteo_q = window.criteo_q || [];
    window.criteo_q.push({
      event: "trackTransaction",
      id: "<?php echo $order->get_order_number(); ?>",
      item: [
        <?php
        foreach ($order->get_items() as $item) {
          $product = $item->get_product();
          echo '{';
          echo 'id: "' . $product->get_id() . '",';
          echo 'price: ' . $item->get_total() / $item->get_quantity() . ',';
          echo 'quantity: ' . $item->get_quantity();
          echo '},';
        }
        ?>
      ]
    });
  </script>
  <?php
}
?>

Important for Transaction Tracking:

  • Fire only once per transaction
  • Use unique, consistent order IDs
  • Include all purchased items
  • Fire only on order confirmation page
  • Implement deduplication logic

Search Event

viewSearch

Track search queries for better retargeting:

window.criteo_q.push({
  event: "viewSearch",
  keywords: "wireless headphones", // Search query
  item: ["PROD_123", "PROD_456", "PROD_789"] // Up to 3 result product IDs (optional)
});

Search Results Implementation:

// Get search query from URL or form
const searchQuery = new URLSearchParams(window.location.search).get('q') ||
                   document.querySelector('#search-input')?.value;

// Get top search results
const searchResults = Array.from(
  document.querySelectorAll('.search-result-item')
).slice(0, 3).map(el => el.dataset.productId);

if (searchQuery) {
  window.criteo_q.push({
    event: "viewSearch",
    keywords: searchQuery,
    item: searchResults.length > 0 ? searchResults : undefined
  });
}

Event Sequencing

Events should fire in this order on each page:

window.criteo_q = window.criteo_q || [];

// 1. Account setup (required, must be first)
window.criteo_q.push({ event: "setAccount", account: 12345 });

// 2. Device type (required, must be second)
window.criteo_q.push({ event: "setSiteType", type: deviceType });

// 3. User identification (optional, if user is logged in)
if (userEmail) {
  window.criteo_q.push({ event: "setEmail", email: userEmail });
}

// 4. Page-specific event (required)
window.criteo_q.push({ event: "viewItem", item: productId });

Data Layer Integration

Standard Data Layer Pattern

// Set up data layer first
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
  pageType: 'product',
  productId: 'PROD_123',
  productPrice: 99.99,
  userId: 'USER_456',
  userEmail: 'user@example.com'
});

// Then fire Criteo events using data layer
window.criteo_q = window.criteo_q || [];
const pageData = window.dataLayer[0];

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

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

switch (pageData.pageType) {
  case 'home':
    window.criteo_q.push({ event: "viewHome" });
    break;
  case 'product':
    window.criteo_q.push({ event: "viewItem", item: pageData.productId });
    break;
  case 'cart':
    window.criteo_q.push({ event: "viewBasket", item: pageData.cartItems });
    break;
  case 'confirmation':
    window.criteo_q.push({
      event: "trackTransaction",
      id: pageData.orderId,
      item: pageData.orderItems
    });
    break;
}

Testing and Validation

Console Testing

// Log all Criteo events
console.log('Criteo Events:', window.criteo_q);

// Verify specific events
window.criteo_q.forEach((event, index) => {
  console.log(`Event ${index}:`, event.event, event);
});

// Monitor new events
const originalPush = window.criteo_q.push;
window.criteo_q.push = function(...args) {
  console.log('New Criteo Event:', args);
  return originalPush.apply(this, args);
};

Event Validation Checklist

  • setAccount is first event with correct account ID
  • setSiteType is second event with correct device type
  • Page-specific event fires (viewHome, viewItem, etc.)
  • Product IDs match product feed exactly
  • Transaction event fires only once per order
  • User email captured for logged-in users
  • No JavaScript errors in console
  • Network requests to criteo.com succeed

Debug Mode

// Enable Criteo debug logging
window.criteo_q.push({
  event: "setAccount",
  account: 12345,
  debug: true
});

Best Practices

  1. Product ID Consistency

    • Use exact same IDs as in product feed
    • Include variant IDs when applicable
    • Avoid changing ID format
  2. Event Deduplication

    • Prevent transaction events from firing multiple times
    • Use session storage or server-side tracking
    • Implement page reload detection
  3. Performance

    • Load OneTag asynchronously
    • Fire events after critical page content
    • Minimize event payload size
  4. Privacy

    • Hash emails before sending
    • Respect user consent preferences
    • Implement opt-out mechanisms
  5. Testing

    • Test in staging before production
    • Verify events in browser console
    • Use Criteo's validation tools
    • Monitor data quality in Criteo dashboard

Next Steps

// SYS.FOOTER