> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joinrefine.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversion Tracking

> Track purchases and attribute conversions to search and recommendations

## 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:

```typescript theme={null}
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

<ParamField body="orderId" type="string" required>
  Unique identifier for the order. Used for deduplication.
</ParamField>

<ParamField body="value" type="number" required>
  Total order value (sum of all items).
</ParamField>

<ParamField body="currency" type="string" required>
  ISO 4217 currency code (e.g., 'USD', 'EUR', 'GBP').
</ParamField>

<ParamField body="items" type="PurchaseItem[]" required>
  Array of purchased items.
</ParamField>

### PurchaseItem

<ParamField body="itemId" type="string" required>
  Product ID matching your catalog.
</ParamField>

<ParamField body="quantity" type="number" required>
  Number of units purchased.
</ParamField>

<ParamField body="unitPrice" type="number" required>
  Price per unit at time of purchase.
</ParamField>

## 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.

<Note>
  Attribution works automatically using the visitor/user ID. You don't need to pass the original serve ID to `trackPurchase`.
</Note>

## Implementation Examples

### Order Confirmation Page

```typescript theme={null}
// 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

<Tabs>
  <Tab title="Shopify">
    ```typescript theme={null}
    // 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)
          }))
        });
      }
    });
    ```
  </Tab>

  <Tab title="WooCommerce">
    ```typescript theme={null}
    // In your theme or custom plugin
    jQuery(document).ready(function($) {
      if ($('body').hasClass('woocommerce-order-received')) {
        const orderData = window.woocommerce_order_data;
        
        refine.events.trackPurchase({
          orderId: orderData.order_id,
          value: orderData.total,
          currency: orderData.currency,
          items: orderData.items.map(item => ({
            itemId: item.sku,
            quantity: item.quantity,
            unitPrice: item.price
          }))
        });
      }
    });
    ```
  </Tab>

  <Tab title="Custom Backend">
    ```typescript theme={null}
    // Server-side tracking (Node.js)
    import { Refine } from '@refine-ai/sdk';

    const refine = new Refine({
      apiKey: process.env.REFINE_API_KEY,
      organizationId: 'org_abc123',
      catalogId: 'cat_xyz789',
      applicationType: 'server'
    });

    async function handleOrderComplete(order: Order, userId: string) {
      // Identify the user who made the purchase
      refine.identify(userId);
      
      refine.events.trackPurchase({
        orderId: order.id,
        value: order.total,
        currency: order.currency,
        items: order.items.map(item => ({
          itemId: item.productId,
          quantity: item.quantity,
          unitPrice: item.unitPrice
        }))
      });

      await refine.events.flush();
    }
    ```
  </Tab>
</Tabs>

## Handling Edge Cases

### Duplicate Prevention

Refine deduplicates purchases by `orderId`. If the same order is tracked multiple times, only the first is recorded.

```typescript theme={null}
// 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:

```typescript theme={null}
// 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:

```typescript theme={null}
// 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:

```typescript theme={null}
// 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:

```typescript theme={null}
// 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:

```typescript theme={null}
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:

```typescript theme={null}
window.addEventListener('beforeunload', () => {
  // SDK handles Beacon API internally during flush
  refine.events.flush();
});
```

## Testing Conversions

Enable debug mode to verify purchase tracking:

```typescript theme={null}
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

<CardGroup cols={2}>
  <Card title="Event Overview" icon="chart-line" href="/sdk/events/overview">
    Complete event tracking guide
  </Card>

  <Card title="Analytics Dashboard" icon="chart-pie" href="/platform-guide/analytics/overview">
    View conversion reports
  </Card>
</CardGroup>
