Skip to main content

Overview

Conversion tracking links purchases back to the search queries and recommendations that drove them. This data powers revenue attribution reporting and improves recommendation models.

Tracking Purchases

Call trackPurchase when an order is completed:
refine.events.trackPurchase({
  orderId: 'order_12345',
  value: 249.97,
  currency: 'USD',
  items: [
    { itemId: 'sku_001', quantity: 1, unitPrice: 149.99 },
    { itemId: 'sku_002', quantity: 2, unitPrice: 49.99 }
  ]
});

Purchase Parameters

orderId
string
required
Unique identifier for the order. Used for deduplication.
value
number
required
Total order value (sum of all items).
currency
string
required
ISO 4217 currency code (e.g., ‘USD’, ‘EUR’, ‘GBP’).
items
PurchaseItem[]
required
Array of purchased items.

PurchaseItem

itemId
string
required
Product ID matching your catalog.
quantity
number
required
Number of units purchased.
unitPrice
number
required
Price per unit at time of purchase.

Attribution

Refine automatically attributes purchases to previous interactions within the attribution window (default: 7 days). The flow:
  1. User searches for “running shoes”
  2. User clicks on product SKU_001
  3. User adds SKU_001 to cart
  4. User completes purchase with SKU_001
The purchase is attributed to the original search.
Attribution works automatically using the visitor/user ID. You don’t need to pass the original serve ID to trackPurchase.

Implementation Examples

Order Confirmation Page

// On order confirmation page
async function trackOrderComplete(order: Order) {
  refine.events.trackPurchase({
    orderId: order.id,
    value: order.total,
    currency: order.currency,
    items: order.lineItems.map(item => ({
      itemId: item.productId,
      quantity: item.quantity,
      unitPrice: item.price
    }))
  });

  // Ensure event is sent before user navigates away
  await refine.events.flush();
}

E-commerce Platform Integration

  • Shopify
  • WooCommerce
  • Custom Backend
// In your Shopify checkout extension or theme
document.addEventListener('DOMContentLoaded', () => {
  // Check if on thank you page
  if (window.Shopify?.checkout?.order_id) {
    const checkout = window.Shopify.checkout;
    
    refine.events.trackPurchase({
      orderId: checkout.order_id.toString(),
      value: parseFloat(checkout.total_price),
      currency: checkout.currency,
      items: checkout.line_items.map(item => ({
        itemId: item.sku || item.variant_id.toString(),
        quantity: item.quantity,
        unitPrice: parseFloat(item.price)
      }))
    });
  }
});

Handling Edge Cases

Duplicate Prevention

Refine deduplicates purchases by orderId. If the same order is tracked multiple times, only the first is recorded.
// Safe to call multiple times with same orderId
refine.events.trackPurchase({ orderId: 'order_123', ... });
refine.events.trackPurchase({ orderId: 'order_123', ... }); // Ignored

Partial Orders

Track only the items that were actually fulfilled:
// Original order had 3 items, but 1 was out of stock
refine.events.trackPurchase({
  orderId: 'order_123',
  value: 199.98,  // Adjusted total
  currency: 'USD',
  items: [
    { itemId: 'sku_001', quantity: 1, unitPrice: 149.99 },
    { itemId: 'sku_002', quantity: 1, unitPrice: 49.99 }
    // sku_003 excluded - out of stock
  ]
});

Refunds

For full refunds, no action needed (attribution is preserved for analytics). For partial refunds, you may optionally track a negative adjustment:
// Optional: Track refund for analytics
refine.events.trackPurchase({
  orderId: 'refund_order_123',
  value: -49.99,
  currency: 'USD',
  items: [
    { itemId: 'sku_002', quantity: -1, unitPrice: 49.99 }
  ]
});

Guest Checkout

For guest checkout, the visitor ID automatically links the purchase to previous interactions:
// No identify() needed - visitor ID handles attribution
refine.events.trackPurchase({
  orderId: 'order_guest_456',
  value: 99.99,
  currency: 'USD',
  items: [{ itemId: 'sku_001', quantity: 1, unitPrice: 99.99 }]
});

Post-Purchase Identification

If the user creates an account after checkout, call identify to link:
// User completes purchase as guest
refine.events.trackPurchase({ orderId: 'order_123', ... });

// Later, user creates account
refine.identify('new_user_789');

// Future purchases and browsing now linked to user account

Ensuring Data Delivery

Always flush events after tracking purchases:
async function onOrderComplete(order: Order) {
  refine.events.trackPurchase({
    orderId: order.id,
    value: order.total,
    currency: order.currency,
    items: order.items
  });

  // Wait for event to be sent
  await refine.events.flush();
  
  // Now safe to redirect
  window.location.href = '/order-confirmation';
}

Beacon API Fallback

For page unloads, the SDK uses the Beacon API when available:
window.addEventListener('beforeunload', () => {
  // SDK handles Beacon API internally during flush
  refine.events.flush();
});

Testing Conversions

Enable debug mode to verify purchase tracking:
const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  debug: true  // Logs all events to console
});

// Track a test purchase
refine.events.trackPurchase({
  orderId: 'test_order_001',
  value: 99.99,
  currency: 'USD',
  items: [{ itemId: 'sku_test', quantity: 1, unitPrice: 99.99 }]
});

// Check console for:
// [Refine] trackPurchase { orderId: 'test_order_001', ... }

Next Steps