AdRoll Event Tracking | Blue Frog Docs

AdRoll Event Tracking

Configure custom conversion events, purchase tracking, lead generation, and product interactions for AdRoll campaign optimization.

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


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, price
  • user_email: Customer email (auto-hashed for privacy)

E-Commerce Platform Implementations

Shopify (Liquid template):

<!-- 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');

Magento 2:

<!-- 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

HTML form with redirect:

<!-- 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_homepage vs. video_watchers
  • Include context: form_submit_contact vs. 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: purchase or transaction
  • 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 sessionStorage to prevent re-fires on page refresh
  • Implement event_id for client+server tracking

Revenue doesn't match actual:

  • Check currency formatting (remove symbols, commas)
  • Verify conversion_value is 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_id to catalog feed
  • Include all required product fields (id, quantity, price)

Next Steps

// SYS.FOOTER