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

# Why Didn't My Purchase Get Attributed?

> Troubleshoot common attribution issues and understand how to debug missing purchase attribution in Topsort campaigns.

export const LastUpdated = ({date, lang = "en"}) => {
  const translations = {
    en: "Last updated:",
    es: "Última actualización:",
    pt: "Última atualização:",
    fr: "Dernière mise à jour:",
    de: "Zuletzt aktualisiert:"
  };
  const label = translations[lang] || translations.en;
  return <>
<style>{`
.last-updated-component {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 16px;
border-radius: 8px;
margin-top: 12px;
margin-bottom: 16px;
font-size: 14px;
background-color: rgba(0, 0, 0, 0.05);
border: 1px solid rgba(0, 0, 0, 0.12);
color: rgba(0, 0, 0, 0.75);
line-height: 1;
}

        .last-updated-component svg {
          flex-shrink: 0;
          vertical-align: middle;
        }

        .last-updated-component span {
          display: inline-flex !important;
          align-items: center !important;
          line-height: 1 !important;
        }

        [data-theme="dark"] .last-updated-component {
          background-color: #3a3a3a;
          border: 2px solid #888888;
          color: #ffffff;
        }

        [data-theme="dark"] .last-updated-component svg {
          stroke: #ffffff;
        }
      `}</style>
      <div className="last-updated-component">
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <circle cx="12" cy="12" r="10" />
          <polyline points="12 6 12 12 16 14" />
        </svg>
        <span>
          <strong style={{
    fontWeight: 600
  }}>{label}</strong> 
          <time dateTime={date}>{date}</time>
        </span>
      </div>
    </>;
};

Attribution connects ad interactions (impressions, clicks) to purchases. When a purchase
doesn't attribute, it's usually one of these reasons:

## Quick Checklist

| Check                                  | How to Verify                                                                     |
| -------------------------------------- | --------------------------------------------------------------------------------- |
| Was there a click or impression first? | Check Events API logs or dashboard                                                |
| Same user ID in both events?           | Compare `opaqueUserId` or `userId` in click vs purchase                           |
| Within attribution window?             | Varies by ad format: 7 days (listings), 14 days (brands), up to 30 days (banners) |
| Same vendor?                           | Purchase must be for a product from the campaign's vendor                         |
| Event actually sent?                   | Check for 200 response from `/v2/events`                                          |

## User ID Matching

Attribution requires the same user identifier in both the ad interaction and the purchase.

| Scenario                         | What to Send                      | Example                             |
| -------------------------------- | --------------------------------- | ----------------------------------- |
| **Logged-in user**               | Your internal user ID             | `userId: "user_12345"`              |
| **Anonymous user (with cookie)** | Consistent opaque ID              | `opaqueUserId: "abc123-session-id"` |
| **Fully anonymous**              | Nothing (no attribution possible) | Cannot attribute                    |

### Common Mistakes

**Wrong: Different IDs for same user**

```json theme={null}
// Click event
{ "opaqueUserId": "session_abc123" }

// Purchase event (same user, but different ID!)
{ "userId": "customer_456" }
```

These won't match. Attribution fails silently.

**Correct: Consistent ID**

```json theme={null}
// Click event
{ "userId": "customer_456" }

// Purchase event
{ "userId": "customer_456" }
```

## Attribution Windows

Attribution windows are configurable per ad format to match how each format influences customer behavior:

| Ad Format              | Typical Window | Range      | Why                                         |
| ---------------------- | -------------- | ---------- | ------------------------------------------- |
| **Sponsored Listings** | 7-14 days      | 1-14 days  | High purchase intent, shorter consideration |
| **Sponsored Brands**   | 14-30 days     | 7-30 days  | Brand consideration period                  |
| **Banner/Video Ads**   | 14-30 days     | 14-30 days | Awareness and discovery focus               |

**Important:** A purchase outside the configured window will **not** attribute to the ad interaction.

**Need different windows?** Contact support to configure custom attribution windows for your ad formats.

For more on attribution concepts, see our [Glossary](/en/overview/glossary).

## Halo Attribution

Halo attribution credits a vendor when a user clicks on Product A but purchases Product B
from the same vendor.

**Requirements:**

* `vendorId` must be included in the purchase event
* Products must belong to the same vendor
* Within attribution window

```json theme={null}
// Purchase event with vendorId for halo attribution
{
  "type": "purchase",
  "userId": "customer_456",
  "productId": "product_B",
  "vendorId": "vendor_123",  // Required for halo
  "items": [...]
}
```

## Debugging Steps

1. **Verify events are arriving**
   * Check dashboard: Events → Recent Events
   * Or query: `GET /public/v1/reporting-service/interactions`

2. **Check for matching user IDs**
   * Export click events and purchase events
   * Compare `userId` or `opaqueUserId` fields

3. **Verify timing**
   * Compare `occurredAt` timestamps
   * Purchase must be within window of click/impression

4. **Check vendor match**
   * For halo: verify `vendorId` is sent with purchase
   * For direct: verify `productId` is in the campaign

## Still Not Working?

If you've verified all the above and attribution still isn't working:

1. Export a sample of unattributed purchases
2. Export clicks from the same time period
3. Contact support with both exports and we'll trace the specific events

<LastUpdated date="2026-01-05" />
