Event Tracking Overview
AdRoll event tracking captures user actions beyond pageviews - purchases, leads, add-to-cart, video views, downloads - for conversion optimization and ROI measurement. Events are sent via the adroll.track() JavaScript method or server-side API calls. Proper event tracking is critical for measuring campaign success, building conversion-based audiences, and optimizing ad delivery for business outcomes.
Event Types
- Purchase: E-commerce transactions with revenue and product details
- Lead: Form submissions, sign-ups, contact requests
- Add-to-cart: Product additions for cart abandonment retargeting
- Page view: Product views, category browsing (enhanced pageviews)
- Custom: Any business-specific action (video plays, downloads, bookings)
Prerequisites
- AdRoll pixel installed and firing (see Install Tag/SDK)
- Confirmation/thank-you pages where conversion events will fire
- Access to edit website code or tag manager
- (For e-commerce) Product data from catalog or data layer
Purchase Conversion Tracking
Basic Purchase Event
Fire on order confirmation/thank-you page:
// Fire AFTER successful purchase
adroll.track("purchase", {
order_id: "ORD-12345", // Required: Unique order ID
currency: "USD", // Required: ISO currency code
conversion_value: 99.99, // Required: Total order value (number)
products: [ // Recommended: Product details
{
product_id: "SKU-001",
quantity: 2,
price: 49.99
}
]
});
Required fields:
order_id: Unique identifier for deduplication (string)currency: ISO 4217 code (USD,EUR,GBP, etc.)conversion_value: Total revenue as number (no currency symbols)
Recommended fields:
products: Array of purchased items with ID, quantity, priceuser_email: Customer email (auto-hashed for privacy)
E-Commerce Platform Implementations
<!-- Create custom code snippet: Snippets → adroll-purchase.liquid -->
{% if first_time_accessed %}
<script>
adroll.track("purchase", {
order_id: "{{ order.name }}",
currency: "{{ shop.currency }}",
conversion_value: {{ checkout.total_price | money_without_currency | remove: ',' }},
products: [
{% for line_item in checkout.line_items %}
{
product_id: "{{ line_item.product_id }}",
quantity: {{ line_item.quantity }},
price: {{ line_item.price | money_without_currency }}
}{% unless forloop.last %},{% endunless %}
{% endfor %}
]
});
</script>
{% endif %}
<!-- Add to checkout.liquid or Settings → Checkout → Order status page -->
{{ content_for_header }}
{% include 'adroll-purchase' %}
WooCommerce (PHP):
// functions.php or custom plugin
function adroll_purchase_tracking() {
// Only fire on order confirmation page
if (!is_order_received_page()) {
return;
}
global $wp;
$order_id = absint($wp->query_vars['order-received']);
if (!$order_id) {
return;
}
$order = wc_get_order($order_id);
if (!$order) {
return;
}
// Build products array
$products = array();
foreach ($order->get_items() as $item) {
$product = $item->get_product();
$products[] = array(
'product_id' => $product->get_sku() ?: $product->get_id(),
'quantity' => $item->get_quantity(),
'price' => floatval($item->get_total()) / $item->get_quantity()
);
}
?>
<script type="text/javascript">
adroll.track("purchase", {
order_id: "<?php echo esc_js($order->get_order_number()); ?>",
currency: "<?php echo esc_js($order->get_currency()); ?>",
conversion_value: <?php echo $order->get_total(); ?>,
products: <?php echo json_encode($products); ?>
});
</script>
<?php
}
add_action('wp_footer', 'adroll_purchase_tracking');
<!-- app/design/frontend/[Vendor]/[Theme]/Magento_Checkout/templates/success.phtml -->
<?php if ($block->getOrderId()): ?>
<?php
$order = $block->getOrder();
$products = [];
foreach ($order->getAllVisibleItems() as $item) {
$products[] = [
'product_id' => $item->getSku(),
'quantity' => (int)$item->getQtyOrdered(),
'price' => (float)$item->getPrice()
];
}
?>
<script type="text/javascript">
adroll.track("purchase", {
order_id: "<?= $block->escapeJs($order->getIncrementId()) ?>",
currency: "<?= $block->escapeJs($order->getOrderCurrencyCode()) ?>",
conversion_value: <?= $order->getGrandTotal() ?>,
products: <?= json_encode($products) ?>
});
</script>
<?php endif; ?>
BigCommerce (Handlebars template):
{{!-- templates/pages/order-confirmation.html --}}
{{#if order}}
<script>
adroll.track("purchase", {
order_id: "{{order.id}}",
currency: "{{order.currency.code}}",
conversion_value: {{order.total_inc_tax}},
products: [
{{#each order.items}}
{
product_id: "{{sku}}",
quantity: {{quantity}},
price: {{price.value}}
}{{#unless @last}},{{/unless}}
{{/each}}
]
});
</script>
{{/if}}
Custom Implementation (Generic)
For custom checkouts or non-standard platforms:
// thank-you.html or confirmation page
<script>
// Get order data from page or URL parameters
const orderId = getOrderIdFromURL(); // Your custom function
const orderTotal = parseFloat(document.getElementById('order-total').textContent);
const currency = 'USD'; // Or detect dynamically
// Fire conversion event
adroll.track("purchase", {
order_id: orderId,
currency: currency,
conversion_value: orderTotal,
products: getProductsFromOrder() // Your function to extract products
});
// Helper function example
function getOrderIdFromURL() {
const params = new URLSearchParams(window.location.search);
return params.get('order_id') || 'unknown';
}
function getProductsFromOrder() {
// Extract from DOM or data layer
return [
{
product_id: document.querySelector('[data-product-id]').dataset.productId,
quantity: parseInt(document.querySelector('[data-quantity]').textContent),
price: parseFloat(document.querySelector('[data-price]').textContent)
}
];
}
</script>
Purchase Event Best Practices
1. Fire only once per order:
// Prevent duplicate conversions on page refresh
if (!sessionStorage.getItem('order_' + orderId + '_tracked')) {
adroll.track("purchase", {
order_id: orderId,
conversion_value: total,
currency: "USD"
});
sessionStorage.setItem('order_' + orderId + '_tracked', 'true');
}
2. Data type validation:
// WRONG - Common mistakes
adroll.track("purchase", {
order_id: 12345, // Should be string
conversion_value: "$99.99", // Should be number, no $
currency: "dollars", // Should be ISO code
products: "SKU-001" // Should be array
});
// CORRECT
adroll.track("purchase", {
order_id: "12345", // String
conversion_value: 99.99, // Number
currency: "USD", // ISO code
products: [{ // Array of objects
product_id: "SKU-001",
quantity: 1,
price: 99.99
}]
});
3. Currency formatting:
// Remove currency symbols and commas
const rawTotal = "$1,234.56";
const cleanTotal = parseFloat(rawTotal.replace(/[$,]/g, '')); // 1234.56
adroll.track("purchase", {
conversion_value: cleanTotal, // Use cleaned number
currency: "USD"
});
4. Multi-currency support:
// Detect currency dynamically
const currency = document.querySelector('[data-currency]')?.dataset.currency || 'USD';
adroll.track("purchase", {
conversion_value: 99.99,
currency: currency // "EUR", "GBP", etc.
});
Lead Generation Tracking
Basic Lead Event
Fire on form submission confirmation:
// Fire on thank-you page after form submit
adroll.track("pageView", {
segment_name: "leads", // Creates "leads" audience
conversion_value: 50, // Estimated lead value (optional)
user_email: "user@example.com" // Auto-hashed for privacy
});
Alternative: Use custom segment:
// For different lead types
adroll.track("pageView", {
segment_name: "newsletter_signups"
});
adroll.track("pageView", {
segment_name: "demo_requests"
});
adroll.track("pageView", {
segment_name: "quote_requests"
});
Form Submission Tracking
<!-- contact-form.html -->
<form action="/thank-you" method="POST">
<input type="email" name="email" required>
<button type="submit">Submit</button>
</form>
<!-- thank-you.html -->
<script>
// Fire lead conversion on thank-you page
adroll.track("pageView", {
segment_name: "contact_form_leads",
conversion_value: 25 // Estimated lead value
});
</script>
AJAX form submission:
// contact-form.js
document.getElementById('contact-form').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
fetch('/api/submit-form', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Fire AdRoll lead event
adroll.track("pageView", {
segment_name: "contact_leads",
user_email: formData.get('email') // Auto-hashed
});
// Show success message
document.getElementById('success-message').style.display = 'block';
}
})
.catch(error => console.error('Form error:', error));
});
CRM Integration (Server-Side)
For server-side lead tracking via API:
// Node.js backend example
const axios = require('axios');
app.post('/api/submit-lead', async (req, res) => {
const { email, name, phone } = req.body;
// Save to your CRM
await saveToCRM({email, name, phone});
// Send to AdRoll API
await axios.post('https://services.adroll.com/api/v1/track', {
advertiser_id: 'ABC123XYZ',
pixel_id: 'DEF456GHI',
event: 'lead',
user_email: email, // AdRoll auto-hashes
properties: {
segment_name: 'crm_leads',
conversion_value: 50
}
}, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
res.json({success: true});
});
Add-to-Cart Tracking
Basic Add-to-Cart Event
Fire when user adds product to cart:
// Fire on "Add to Cart" button click
adroll.track("addToCart", {
product_id: "SKU-001",
quantity: 1,
price: 49.99,
currency: "USD"
});
E-Commerce Implementations
Shopify (theme.js or custom script):
// Listen for Shopify cart add events
document.addEventListener('DOMContentLoaded', function() {
// Shopify AJAX cart add
document.querySelectorAll('form[action="/cart/add"]').forEach(form => {
form.addEventListener('submit', function(e) {
const formData = new FormData(this);
const productId = formData.get('id');
const quantity = parseInt(formData.get('quantity') || 1);
// Get product data from form or page
const price = parseFloat(
this.querySelector('[data-price]')?.dataset.price || 0
);
adroll.track("addToCart", {
product_id: productId,
quantity: quantity,
price: price,
currency: "{{ shop.currency }}"
});
});
});
});
WooCommerce (custom JS):
// enqueue in functions.php or custom plugin
jQuery(document).ready(function($) {
// WooCommerce add to cart button click
$(document).on('click', '.add_to_cart_button', function() {
const $button = $(this);
const productId = $button.data('product_id');
const quantity = parseInt($button.data('quantity') || 1);
const price = parseFloat($button.data('price') || 0);
adroll.track("addToCart", {
product_id: productId,
quantity: quantity,
price: price,
currency: woocommerce_params.currency // From WooCommerce
});
});
});
Custom implementation:
// Generic add-to-cart tracking
document.querySelectorAll('.add-to-cart-btn').forEach(button => {
button.addEventListener('click', function(e) {
const productId = this.dataset.productId;
const quantity = parseInt(this.dataset.quantity || 1);
const price = parseFloat(this.dataset.price);
adroll.track("addToCart", {
product_id: productId,
quantity: quantity,
price: price,
currency: "USD"
});
// Continue with normal cart add process
});
});
Enhanced Page View Tracking
Product Page Views
Track product detail page visits with product data:
// Fire on product detail pages
adroll.track("pageView", {
product_id: "SKU-001",
product_name: "Premium Widget",
category: "Widgets",
price: 49.99,
image_url: "https://example.com/images/widget.jpg",
url: "https://example.com/products/premium-widget",
inventory_status: "in_stock"
});
E-commerce platform examples:
Shopify (product.liquid):
<!-- templates/product.liquid -->
<script>
adroll.track("pageView", {
product_id: "{{ product.id }}",
product_name: "{{ product.title | escape }}",
category: "{{ product.type }}",
price: {{ product.price | money_without_currency }},
image_url: "{{ product.featured_image | img_url: 'large' }}",
url: "{{ shop.url }}{{ product.url }}",
inventory_status: "{% if product.available %}in_stock{% else %}out_of_stock{% endif %}"
});
</script>
WooCommerce (functions.php):
function adroll_product_tracking() {
if (!is_product()) {
return;
}
global $product;
?>
<script>
adroll.track("pageView", {
product_id: "<?php echo esc_js($product->get_sku() ?: $product->get_id()); ?>",
product_name: "<?php echo esc_js($product->get_name()); ?>",
category: "<?php echo esc_js(wp_strip_all_tags(wc_get_product_category_list($product->get_id()))); ?>",
price: <?php echo $product->get_price(); ?>,
image_url: "<?php echo esc_url(wp_get_attachment_url($product->get_image_id())); ?>",
url: "<?php echo esc_url(get_permalink()); ?>",
inventory_status: "<?php echo $product->is_in_stock() ? 'in_stock' : 'out_of_stock'; ?>"
});
</script>
<?php
}
add_action('wp_footer', 'adroll_product_tracking');
Category Page Tracking
Track category browsing for audience segmentation:
// Fire on category/collection pages
adroll.track("pageView", {
segment_name: "category_widgets", // Custom audience segment
category: "Widgets",
page_type: "category"
});
Example: Shopify collection pages:
<!-- templates/collection.liquid -->
<script>
adroll.track("pageView", {
segment_name: "category_{{ collection.handle }}",
category: "{{ collection.title | escape }}",
page_type: "collection"
});
</script>
Custom Event Tracking
Define Custom Events
Track business-specific actions:
// Video play tracking
adroll.track("pageView", {
segment_name: "video_viewers",
video_title: "Product Demo",
video_duration: 120 // seconds
});
// File download tracking
adroll.track("pageView", {
segment_name: "whitepaper_downloads",
file_name: "2025-Industry-Report.pdf"
});
// Booking/reservation tracking
adroll.track("pageView", {
segment_name: "appointment_bookings",
service_type: "consultation",
booking_date: "2025-01-15"
});
// Quiz/survey completion
adroll.track("pageView", {
segment_name: "quiz_completers",
quiz_name: "Product Finder",
quiz_result: "Widget Pro"
});
Event Naming Conventions
Best practices:
// GOOD - Descriptive, consistent naming
segment_name: "demo_requests"
segment_name: "trial_signups"
segment_name: "video_watchers_product_demo"
// AVOID - Vague or inconsistent
segment_name: "segment1"
segment_name: "users" // Too broad
segment_name: "DemoRequests" // Inconsistent casing
Naming strategy:
- Use lowercase with underscores:
demo_requests - Be specific:
video_watchers_homepagevs.video_watchers - Include context:
form_submit_contactvs.form_submit_newsletter - Document all custom segments for team reference
Google Tag Manager Event Tracking
Purchase Event via GTM
1. Create data layer variables:
- Variables → New → Data Layer Variable
- Variable names:
transactionId,transactionTotal,transactionCurrency
2. Create conversion tag:
- Tags → New → Custom HTML
- Tag name:
AdRoll - Purchase Conversion
<script>
adroll.track("purchase", {
order_id: {{transactionId}},
conversion_value: {{transactionTotal}},
currency: {{transactionCurrency}},
products: {{transactionProducts}} // GTM variable with product array
});
</script>
3. Set trigger:
- Triggering → New Trigger → Custom Event
- Event name:
purchaseortransaction - Fire when:
{{transactionId}}is not empty
4. Test and publish:
- Use GTM Preview Mode
- Complete test purchase
- Verify tag fires with correct data
Custom Event via GTM
<!-- GTM Custom HTML Tag: AdRoll - Lead Tracking -->
<script>
adroll.track("pageView", {
segment_name: "contact_leads",
conversion_value: {{leadValue}} // GTM variable
});
</script>
<!-- Trigger: Custom Event -->
<!-- Event name: form_submit -->
<!-- Fire when: {{formName}} equals "contact_form" -->
Server-Side Event Tracking
AdRoll API Event Tracking
For server-side conversions (bypasses ad blockers):
// Node.js example
const axios = require('axios');
async function trackAdRollConversion(orderData) {
try {
const response = await axios.post(
'https://services.adroll.com/api/v1/track',
{
advertiser_id: 'ABC123XYZ',
pixel_id: 'DEF456GHI',
event: 'purchase',
user_id: hashEmail(orderData.email), // SHA256 hash
event_id: orderData.orderId, // For deduplication
properties: {
order_id: orderData.orderId,
conversion_value: orderData.total,
currency: orderData.currency,
products: orderData.items.map(item => ({
product_id: item.sku,
quantity: item.quantity,
price: item.price
}))
},
timestamp: Math.floor(Date.now() / 1000)
},
{
headers: {
'Authorization': `Bearer ${process.env.ADROLL_API_KEY}`,
'Content-Type': 'application/json'
}
}
);
console.log('AdRoll conversion tracked:', response.data);
} catch (error) {
console.error('AdRoll API error:', error.response?.data || error.message);
}
}
// Hash email for privacy
const crypto = require('crypto');
function hashEmail(email) {
return crypto.createHash('sha256').update(email.toLowerCase().trim()).digest('hex');
}
// Usage: After order is saved to database
app.post('/api/checkout', async (req, res) => {
const order = await saveOrder(req.body);
// Track server-side
await trackAdRollConversion({
orderId: order.id,
email: order.customerEmail,
total: order.total,
currency: order.currency,
items: order.lineItems
});
res.json({success: true, orderId: order.id});
});
Deduplication (Client + Server Tracking)
Prevent double-counting when using both client and server-side:
// Client-side (browser)
const eventId = 'evt_' + Date.now() + '_' + Math.random();
adroll.track("purchase", {
order_id: "ORD-123",
conversion_value: 99.99,
currency: "USD",
event_id: eventId // Deduplication key
});
// Also send event_id to server
fetch('/api/track-conversion', {
method: 'POST',
body: JSON.stringify({
order_id: "ORD-123",
event_id: eventId // Same ID
})
});
// Server-side
// Use same event_id in API call
// AdRoll deduplicates based on event_id
Testing & Validation
Test Events in Browser Console
// Manually trigger test events
// Open browser console (F12)
// Test purchase
adroll.track("purchase", {
order_id: "TEST-" + Date.now(),
conversion_value: 10.00,
currency: "USD",
products: [{product_id: "TEST", quantity: 1, price: 10.00}]
});
// Test lead
adroll.track("pageView", {
segment_name: "test_leads"
});
// Test add-to-cart
adroll.track("addToCart", {
product_id: "TEST-SKU",
quantity: 1,
price: 5.00,
currency: "USD"
});
// Check Network tab for POST to d.adroll.com
// Events should appear in AdRoll dashboard within 24-48 hours
Verify in AdRoll Dashboard
1. Conversion reports:
- AdRoll → Reports → Conversions
- Filter by date range including test
- Look for test order IDs
2. Audience segments:
- AdRoll → Audiences → [Custom Segment]
- Check audience size increases after events fire
- May take 24-48 hours to populate
3. Recent activity:
- Settings → Pixels → View Recent Events
- Shows recent pageviews and conversions
- Useful for real-time validation
Event Validation Checklist
For each event type:
- Event fires on correct page/action
- Required fields present (order_id, conversion_value, etc.)
- Data types correct (numbers not strings)
- Currency formatting correct (no symbols, valid ISO code)
- No JavaScript errors in console
- Network request succeeds (200 OK response)
- Deduplication logic prevents double-firing
- Events appear in dashboard within 48 hours
Common Event Tracking Issues
Events fire but don't appear in dashboard:
- Wait 24-48 hours for data processing
- Verify approved domains include event source domain
- Check conversion attribution windows (may be outside window)
Duplicate conversions:
- Add deduplication logic with unique
order_id - Use
sessionStorageto prevent re-fires on page refresh - Implement
event_idfor client+server tracking
Revenue doesn't match actual:
- Check currency formatting (remove symbols, commas)
- Verify
conversion_valueis total order value (including tax/shipping if desired) - Ensure data type is number, not string
Products not showing in reports:
- Validate products array syntax (array of objects)
- Match
product_idto catalog feed - Include all required product fields (id, quantity, price)
Next Steps
- Data Layer Setup - Configure product catalog for dynamic ads
- Troubleshooting & Debugging - Fix event tracking issues
- Server-Side vs Client-Side - API tracking implementation