This guide provides solutions to common Criteo implementation issues, debugging techniques, and best practices for maintaining a healthy Criteo integration.
OneTag Troubleshooting
Verify OneTag Installation
Check if the OneTag is properly loaded on your pages:
// Open browser console and run:
console.log(window.criteo_q);
// Should return an array of event objects
// Example output:
// [
// {event: "setAccount", account: 12345},
// {event: "setSiteType", type: "d"},
// {event: "viewItem", item: "PROD123"}
// ]
Common OneTag Issues
1. OneTag Not Loading
Symptoms:
window.criteo_qis undefined- No Criteo requests in Network tab
Diagnosis:
// Check if script is blocked
if (typeof window.criteo_q === 'undefined') {
console.error('Criteo OneTag not loaded');
}
// Check Network tab for:
// - dynamic.criteo.com/js/ld/ld.js
// - gum.criteo.com/syncframe
Solutions:
- Verify script tag is present in HTML
- Check for ad blocker interference
- Ensure script is not blocked by Content Security Policy
<!-- Add to CSP header if needed -->
<meta http-equiv="Content-Security-Policy"
content="script-src 'self' dynamic.criteo.com gum.criteo.com">
- Check for JavaScript errors preventing execution
2. Incorrect Account ID
Symptoms:
- Events fire but no data appears in Criteo dashboard
- Console errors about invalid account
Diagnosis:
// Verify account ID in console
window.criteo_q.forEach(event => {
if (event.event === 'setAccount') {
console.log('Account ID:', event.account);
}
});
Solutions:
- Verify account ID in Criteo Management Center under Settings > Account Information
- Ensure account ID is a number, not a string:
// ✗ Wrong
{ event: "setAccount", account: "12345" }
// ✓ Correct
{ event: "setAccount", account: 12345 }
3. Events Not Firing
Symptoms:
- OneTag loads but specific events don't trigger
- Product views not recorded
Diagnosis:
// Add debug listener
window.criteo_q.push = function(...args) {
console.log('Criteo event pushed:', args);
return Array.prototype.push.apply(this, args);
};
Solutions:
- Check event syntax matches Criteo specifications
- Verify events fire on correct page types
- Ensure data layer is populated before OneTag executes
// ✓ Correct order
<script>
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
productId: 'PROD123',
productPrice: 99.99
});
</script>
<script src="//dynamic.criteo.com/js/ld/ld.js" async="true"></script>
<script>
window.criteo_q = window.criteo_q || [];
window.criteo_q.push({
event: "viewItem",
item: window.dataLayer[0].productId
});
</script>
4. Device Type Detection Issues
Symptoms:
- Incorrect device type classification
- Mobile traffic showing as desktop
Diagnosis:
// Test device type detection
var deviceType = /iPad/.test(navigator.userAgent) ? "t" :
/Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Silk/.test(navigator.userAgent) ? "m" : "d";
console.log('Detected device type:', deviceType);
// t = tablet, m = mobile, d = desktop
Solutions:
- Use improved device detection:
function getCriteoDeviceType() {
const ua = navigator.userAgent;
// Tablet detection
if (/(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test(ua.toLowerCase())) {
return 't';
}
// Mobile detection
if (/(mobi|ipod|phone|blackberry|opera mini|fennec|minimo|symbian|psp|nintendo ds|archos|skyfire|puffin|blazer|bolt|gobrowser|iris|maemo|semc|teashark|uzard)/.test(ua.toLowerCase())) {
return 'm';
}
// Desktop
return 'd';
}
window.criteo_q.push({
event: "setSiteType",
type: getCriteoDeviceType()
});
Product Feed Issues
Feed Validation Errors
1. Missing Required Fields
Error Message:
"Feed rejected: Missing required field 'image_link' for product PROD123"
Solutions:
Verify all required fields are present:
idtitledescriptionlinkimage_linkpriceavailability
Check XML structure:
<!-- ✗ Wrong - missing image_link -->
<product>
<id>PROD123</id>
<title>Product Name</title>
<link>https://example.com/product</link>
<price>99.99 USD</price>
</product>
<!-- ✓ Correct -->
<product>
<id>PROD123</id>
<title>Product Name</title>
<description>Product description</description>
<link>https://example.com/product</link>
<image_link>https://example.com/images/product.jpg</image_link>
<price>99.99 USD</price>
<availability>in stock</availability>
</product>
2. Invalid URL Format
Error Message:
"Invalid URL format in field 'link' for product PROD456"
Solutions:
- Ensure all URLs are absolute and use HTTPS:
<!-- ✗ Wrong -->
<link>/products/item</link>
<image_link>http://example.com/image.jpg</image_link>
<!-- ✓ Correct -->
<link>https://example.com/products/item</link>
<image_link>https://example.com/images/product.jpg</image_link>
- URL encode special characters:
from urllib.parse import quote
# Encode product URLs
product_url = "https://example.com/product?id=123&variant=blue"
encoded_url = quote(product_url, safe=':/?#[]@!$&\'()*+,;=')
3. Price Format Errors
Error Message:
"Invalid price format for product PROD789"
Solutions:
- Use correct price format:
<!-- ✗ Wrong -->
<price>$99.99</price>
<price>99,99 EUR</price>
<price>99.99</price>
<!-- ✓ Correct -->
<price>99.99 USD</price>
<price>99.99 EUR</price>
<price>99.99 GBP</price>
- Validate currency codes (use ISO 4217):
const validCurrencies = ['USD', 'EUR', 'GBP', 'CAD', 'AUD', 'JPY'];
function formatPrice(amount, currency) {
if (!validCurrencies.includes(currency)) {
throw new Error(`Invalid currency: ${currency}`);
}
return `${parseFloat(amount).toFixed(2)} ${currency}`;
}
4. Character Encoding Issues
Error Message:
"Invalid character encoding in feed"
Solutions:
- Ensure UTF-8 encoding:
<?xml version="1.0" encoding="UTF-8"?>
- Properly escape special characters:
<title>Product & Accessories</title>
<description>Product with "quotes" and <tags></description>
- Use CDATA for HTML content:
<description><![CDATA[
<p>Rich product description with <strong>HTML</strong> formatting</p>
]]></description>
Feed Access Issues
1. Feed Not Accessible
Error Message:
"Unable to access feed URL: Connection timeout"
Diagnosis:
# Test feed accessibility
curl -I https://example.com/feeds/products.xml
# Should return 200 OK
# Check response time (should be < 30 seconds)
Solutions:
- Verify URL is publicly accessible (not behind authentication)
- Check server response time
- Enable HTTPS for feed URL
- Whitelist Criteo's IP addresses if firewall is blocking
Criteo Crawler IPs to Whitelist:
185.31.17.0/24
185.31.18.0/24
185.31.19.0/24
2. Feed Parsing Errors
Error Message:
"XML parsing error at line 145: Unexpected end of file"
Diagnosis:
- Validate XML structure:
# Use xmllint to validate
xmllint --noout products.xml
# Or online validators
curl -X POST https://validator.w3.org/feed/check.cgi \
-d "url=https://example.com/feeds/products.xml"
Solutions:
- Fix malformed XML:
<!-- ✗ Wrong - unclosed tag -->
<product>
<id>123</id>
<title>Product Name
<!-- ✓ Correct -->
<product>
<id>123</id>
<title>Product Name</title>
</product>
- Ensure proper nesting:
<!-- ✗ Wrong -->
<product>
<id>123</id>
<title>Name
</product>
</title>
<!-- ✓ Correct -->
<product>
<id>123</id>
<title>Name</title>
</product>
Event Tracking Debugging
Transaction Not Recorded
Symptoms:
- Purchases not showing in Criteo reports
- Conversion tracking incomplete
Diagnosis:
// Check transaction event on confirmation page
console.log(window.criteo_q);
// Look for trackTransaction event:
// {
// event: "trackTransaction",
// id: "ORDER123",
// item: [
// { id: "PROD1", price: 49.99, quantity: 1 },
// { id: "PROD2", price: 29.99, quantity: 2 }
// ]
// }
Solutions:
- Verify transaction event fires on order confirmation page only
- Check transaction ID format:
// ✗ Wrong - missing transaction details
window.criteo_q.push({
event: "trackTransaction",
id: "12345"
});
// ✓ Correct
window.criteo_q.push({
event: "trackTransaction",
id: "ORD-12345",
item: [
{ id: "PROD123", price: 99.99, quantity: 1 },
{ id: "PROD456", price: 49.99, quantity: 2 }
]
});
- Ensure transaction fires only once:
// Prevent duplicate firing
if (!sessionStorage.getItem('criteo_transaction_fired')) {
window.criteo_q.push({
event: "trackTransaction",
id: orderData.transactionId,
item: orderData.items
});
sessionStorage.setItem('criteo_transaction_fired', 'true');
}
User Email Not Capturing
Symptoms:
- Email-based retargeting not working
- Audience sizes lower than expected
Diagnosis:
// Check email event
window.criteo_q.forEach(event => {
if (event.event === 'setEmail' || event.event === 'setHashedEmail') {
console.log('Email event:', event);
}
});
Solutions:
- Hash emails client-side for privacy:
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('');
}
// Usage
const userEmail = 'User@Example.com';
const hashedEmail = await hashEmail(userEmail);
window.criteo_q.push({
event: "setHashedEmail",
email: hashedEmail
});
- Set email on all page types:
// Set email when available (logged-in users)
if (typeof userEmail !== 'undefined' && userEmail) {
window.criteo_q.push({
event: "setEmail",
email: userEmail,
hash_method: "sha256"
});
}
Browser Console Debugging
Enable Criteo Debug Mode
// Add debug parameter to see detailed logs
window.criteo_q.push({
event: "setAccount",
account: 12345,
debug: true
});
// Monitor Criteo requests
window.criteo_q.push({
event: "debug",
enabled: true
});
Network Tab Analysis
What to Check:
OneTag Script Load
- URL:
https://dynamic.criteo.com/js/ld/ld.js - Status: 200 OK
- Type: script
- URL:
Event Beacon Requests
- URL:
https://sslwidget.criteo.com/* - Status: 200 OK or 204 No Content
- Type: xhr or img
- URL:
User Sync Requests
- URL:
https://gum.criteo.com/syncframe - Status: 200 OK
- URL:
Common Network Issues:
// Issue: CORS errors
// Solution: Criteo handles CORS, but verify no proxy is interfering
// Issue: 403 Forbidden
// Possible cause: Invalid account ID or disabled account
// Check account status in Criteo Management Center
// Issue: Request blocked
// Possible cause: Ad blocker
// Test in incognito mode with ad blockers disabled
Console Error Messages
"Criteo account not set"
// ✗ Wrong - account event missing or after other events
window.criteo_q.push({ event: "viewItem", item: "123" });
window.criteo_q.push({ event: "setAccount", account: 12345 });
// ✓ Correct - account must be first
window.criteo_q.push({ event: "setAccount", account: 12345 });
window.criteo_q.push({ event: "setSiteType", type: "d" });
window.criteo_q.push({ event: "viewItem", item: "123" });
"Invalid event format"
// ✗ Wrong
window.criteo_q.push({
event: "viewItem",
productId: "123" // incorrect parameter name
});
// ✓ Correct
window.criteo_q.push({
event: "viewItem",
item: "123" // correct parameter name
});
Tag Manager Debugging
Google Tag Manager Issues
Preview Mode Testing:
- Enable GTM Preview mode
- Navigate through site
- Check Criteo tags fire on correct triggers
- Verify data layer variables populate correctly
Common GTM Issues:
// Issue: Race condition - data layer not ready
// Solution: Use Custom Event trigger
// ✗ Wrong - fires before data layer populates
dataLayer.push({
event: 'pageview',
productId: getProductId() // async function
});
// ✓ Correct - wait for data
async function pushCriteoEvent() {
const productId = await getProductId();
dataLayer.push({
event: 'criteo_ready',
productId: productId
});
}
Debugging GTM Variables:
// Check GTM variables in console
google_tag_manager['GTM-XXXXX'].dataLayer.get('criteo_account_id');
google_tag_manager['GTM-XXXXX'].dataLayer.get('productId');
Adobe Launch Debugging
Enable debug mode:
// In console
_satellite.setDebug(true);
// Check rule firing
_satellite.track('criteo_product_view');
Performance Issues
Slow Page Load Times
Diagnosis:
// Measure OneTag impact
performance.mark('criteo-start');
// OneTag loads here
performance.mark('criteo-end');
performance.measure('criteo-load', 'criteo-start', 'criteo-end');
const measure = performance.getEntriesByName('criteo-load')[0];
console.log(`Criteo load time: ${measure.duration}ms`);
Solutions:
- Ensure async loading:
<!-- ✓ Correct - async loading -->
<script type="text/javascript" src="//dynamic.criteo.com/js/ld/ld.js" async="true"></script>
<!-- ✗ Wrong - synchronous blocking -->
<script type="text/javascript" src="//dynamic.criteo.com/js/ld/ld.js"></script>
- Load OneTag after critical content:
<script>
// Load Criteo after page is interactive
if (document.readyState === 'complete') {
loadCriteoTag();
} else {
window.addEventListener('load', loadCriteoTag);
}
function loadCriteoTag() {
const script = document.createElement('script');
script.src = '//dynamic.criteo.com/js/ld/ld.js';
script.async = true;
document.head.appendChild(script);
}
</script>
Data Discrepancies
Conversion Count Mismatches
Common Causes:
- Duplicate Transactions - Transaction event fires multiple times
- Missing Deduplication - No order ID tracking
- Time Zone Differences - Criteo vs. analytics platform time zones
- Attribution Models - Different attribution windows
Solutions:
- Implement transaction deduplication:
const firedTransactions = new Set();
function trackTransaction(orderId, items) {
if (firedTransactions.has(orderId)) {
console.log('Transaction already tracked:', orderId);
return;
}
window.criteo_q.push({
event: "trackTransaction",
id: orderId,
item: items
});
firedTransactions.add(orderId);
sessionStorage.setItem('criteo_transactions',
JSON.stringify([...firedTransactions]));
}
- Use consistent order IDs across platforms
Product View Count Discrepancies
Investigation Steps:
- Check if viewItem fires on all product page variants
- Verify product IDs match feed IDs exactly
- Ensure events don't fire on category pages
// Verify product ID consistency
const feedProductId = "PROD123";
const criteoEventProductId = "PROD123"; // Must match exactly
// ✗ Wrong - IDs don't match
// Feed: "PROD123"
// Event: "prod-123" or "123"
Testing Tools
Criteo OneTag Tester Extension
Use browser extensions for real-time debugging:
- Criteo OneTag Checker (Chrome/Firefox)
- Shows active OneTag events
- Validates event format
- Displays account configuration
Feed Validator Tools
# Validate feed locally
python3 validate_criteo_feed.py products.xml
# Online validation
# Use Criteo's feed validation tool in Management Center
# Settings > Catalog > Feed Health
cURL Testing
# Test feed accessibility
curl -I -L https://example.com/feeds/products.xml
# Download and inspect feed
curl -o feed.xml https://example.com/feeds/products.xml
# Test with Criteo user agent
curl -A "Criteo/1.0" https://example.com/feeds/products.xml
Best Practices for Prevention
Implement Comprehensive Testing
- Test OneTag in staging before production
- Validate feed in test environment
- Use automated monitoring
Monitor Feed Health
- Set up alerts for feed failures
- Check feed processing status daily
- Review error reports in Criteo dashboard
Version Control
- Track OneTag changes in version control
- Document customizations
- Maintain rollback capability
Regular Audits
- Monthly OneTag verification
- Quarterly feed quality reviews
- Annual implementation audits
Documentation
- Maintain implementation documentation
- Document customizations and edge cases
- Keep troubleshooting runbook updated
Getting Help
Criteo Support Resources
- Criteo Help Center: https://help.criteo.com
- Technical Documentation: https://help.criteo.com/kb/guide/en/all-criteo-onetag-events
- Support Ticket: Submit via Criteo Management Center
- Account Manager: Contact for account-specific issues
Information to Provide
When contacting support, include:
- Account ID
- Affected page URLs
- Browser console errors
- Network tab screenshots
- Feed URL (if feed-related)
- Steps to reproduce issue