
Tracking affiliate conversions means being able to answer one precise question: which affiliate brought the customer who just paid? Get that wrong, and you either pay commissions to the wrong affiliate or pay nothing at all — and the affiliate who sent you a paying customer has no way to prove it.

Tracking infrastructure gaps are silent: no error, no alert, just an attribution that never formed. Audit them separately from fraud so each risk has an observable signal.

This guide covers the three methods for tracking affiliate conversions, how to choose between them, and how to implement each one with concrete code. If you want to understand *why* tracking breaks, read the [diagnostic companion article on affiliate tracking failures](/en/blog/affiliate-tracking-how-it-works) first. This article picks up where that one ends: at the implementation.

If your immediate question is Stripe-specific, pair this article with the [Stripe affiliate tracking guide](/en/guides/stripe-affiliate-tracking) and the [Stripe affiliate software page](/en/stripe-affiliate-software). Those pages cover the Checkout metadata and webhook paths in a narrower SaaS context.

---

## The three methods for tracking affiliate conversions

### Method 1: First-party cookie tracking

A prospect clicks an affiliate link. Your server reads the affiliate code from the URL parameter and writes a first-party cookie — one issued by your own domain, not a third-party platform domain — to the browser. That cookie persists until it expires or the user clears it.

At conversion time, your signup or checkout handler reads the cookie, retrieves the affiliate ID, and stores it against the user record.

This is the baseline method. It works reliably when the buyer uses the same browser on the same device from click to purchase. It breaks under Safari ITP, ad blockers, and cross-device journeys.

### Method 2: Server-to-server postback (S2S)

Instead of relying on the browser, the merchant's server sends an HTTP POST directly to the affiliate platform's endpoint when a conversion event fires. No browser is involved. The conversion signal travels server-to-server.

S2S postback is the standard in performance marketing networks. It requires that the affiliate tracking link stamps a unique click ID — `clickid` or equivalent — into the landing URL, that your server captures and stores that click ID at landing, and that your confirmation logic can look up the click ID at the moment of conversion to build the postback URL.

S2S avoids browser-side blockers for the conversion signal because no JavaScript executes on the browser side at conversion time. Its weakness is setup complexity and the requirement that click IDs persist server-side through the whole funnel.

### Method 3: Payment-processor metadata (Stripe-native)

The most robust method for Stripe-based SaaS products is to carry the affiliate session identifier directly inside the Stripe payment object as metadata, then process conversions from webhook events.

When a prospect lands on your site via an affiliate link, a cookie stores the session ID. When that session reaches checkout, your backend reads the session ID from the cookie and attaches it to the Stripe object — PaymentIntent, Checkout Session, or Subscription — as metadata. Stripe fires a webhook on payment confirmation. Your backend reads the metadata from the webhook payload and creates the commission. The browser's state at payment time is irrelevant.

This is server-side tracking: the attribution lives in Stripe's infrastructure, not in a cookie.

---

## Comparison table

| Method | Reliability | Resistant to Safari ITP and ad blockers | Implementation complexity |
|---|---|---|---|
| First-party cookie | Medium — drops on Safari, ad blockers, cross-device | No | Low |
| Server-to-server postback | High — no browser dependency at conversion | Yes | Medium |
| Stripe metadata (server-side) | High — attribution lives in Stripe | Yes | Low–Medium (with an SDK) |

In practice, the most resilient setup layers a consented browser session with a server-side conversion signal: after consent, the SDK captures the referral in a first-party cookie, and checkout writes that session ID into Stripe metadata. If no browser session exists, independently known information such as a coupon or server-side affiliate code can provide another path.

---

## Attribution: window, model, and cross-device fallback

### The attribution window

The attribution window is the period during which a click can generate a commission. A click on day 1 inside a 90-day window can credit a conversion on day 88. A click on day 1 inside a 30-day window cannot credit a conversion on day 35.

The window must match your sales cycle, not a platform default. The [diagnostic article on affiliate tracking](/en/blog/affiliate-tracking-how-it-works) reports a 28-day median between first click and first paid transaction in SaaS B2B programs — but that is a median, not a ceiling. 20% of conversions arrive after day 45. A 30-day window structurally loses that tail.

RefCampaign uses a 90-day attribution window. When the visitor grants attribution consent on a landing URL containing `?ref=...`, the browser SDK creates the first-party `_rc_sid` cookie with a 90-day expiry. Refusal creates no session.

### The attribution model

The default model is last-click: whichever affiliate link was clicked most recently before conversion receives 100% of the commission. Last-click is simple to implement, easy to audit, and aligns commission with the conversion event. It is the right default for most SaaS programs.

Last-click has a known weakness: it rewards affiliates who intercept at the bottom of the funnel — coupon sites, cashback platforms — at the expense of those who introduced the product. If your affiliate mix includes a significant share of content publishers doing top-of-funnel work, consider whether last-click incentives match the traffic you want.

### Cross-device fallback via hashed email

Cross-device attribution addresses the scenario where a user clicks an affiliate link on one device and completes signup or purchase on another. The cookie written on device A does not exist on device B.

The solution is to link the click record to an identity signal that is device-independent. Email is the most practical option. After login or signup, when the user's email is known, your tracking layer hashes the email client-side and attaches it to the original click record. If a conversion arrives on a second device without a cookie, the system can look up prior click records associated with that email hash.

This fallback handles the B2B pattern where prospects research on personal devices and purchase on work devices. Measure its contribution by comparing account-linked attribution with browser-only click records.

---

## Anti-fraud signals

Anti-fraud in affiliate tracking is a detection problem, not a blocking problem. Automatic blocking creates false positives — legitimate affiliates who drive real traffic from unusual patterns get excluded, and you never know you lost the conversion.

The correct posture is to flag suspicious signals and surface them for human review. The merchant decides.

| Signal | What it indicates |
|---|---|
| Repeated clicks from the same IP within seconds of each other | Bot or click inflation |
| One IP firing dozens of clicks in a short window | Automated traffic |
| Click-to-conversion interval under 5 minutes | Bot completing signup flow |
| Conversion rate far above the program average for a single affiliate | Likely self-referral or paid traffic laundering |
| Near-identical, evenly spaced click intervals | Scripted click generation |

Flagging, not blocking. Every flagged conversion stays in the queue. The merchant reviews and approves or rejects.

---

## Implementing conversion tracking with RefCampaign

This section walks through the four implementation steps. The code targets RefCampaign SDK v4's consent-gated browser flow.

### Step 1: Load the tracking script

Place the passive v4 script in the `<head>` of your marketing site and app, using the public site token shown in the RefCampaign dashboard. Loading it does not create a session or send a capture request.

```html
<script src="https://sdk.refcampaign.com/v4.js?s=rcst_PUBLIC_SITE_TOKEN" async></script>
```

Connect your consent-management platform to the SDK and replay the persisted choice after every page load:

```js
function applyAttributionConsent(granted) {
  return window.RefCampaignBrowser.setConsent({ attribution: granted })
}
```

The affiliate link redirects to the merchant site with a public alias such as `?ref=fabrice`; the redirect itself sets no cookie and records no click. After a grant, the SDK exchanges that alias for a session and writes `_rc_sid` on the merchant host. An initial refusal creates no session, and a later withdrawal calls the false branch to remove the current attribution state.

### Step 2: Pass the session to Stripe at checkout

Read the `_rc_sid` cookie server-side at checkout creation time and attach it to the Stripe object as `refcampaign_session` metadata.

For one-time payments via PaymentIntent:

```ts
const paymentIntent = await stripe.paymentIntents.create({
  amount: 2400,
  currency: 'eur',
  metadata: sessionId ? { refcampaign_session: sessionId } : {},
})
```

For subscriptions via Checkout Session, attach the metadata to both the session and `subscription_data` — the session metadata covers the checkout event, and `subscription_data.metadata` carries the value forward to every renewal webhook:

```ts
const sessionId = req.cookies.get('_rc_sid')?.value
const metadata = sessionId ? { refcampaign_session: sessionId } : {}

const checkout = await stripe.checkout.sessions.create({
  line_items: [{ price: priceId, quantity: 1 }],
  metadata,
  subscription_data: { metadata },
  mode: 'subscription',
  success_url: `${appUrl}/success`,
  cancel_url: `${appUrl}/pricing`,
})
```

Place `refcampaign_session` on the **Subscription**, not the Customer object, for recurring payments. Each subscription is tied to one specific affiliate referral. A customer who cancels and resubscribes via a different affiliate link creates a new subscription — the new link gets credited, not the original one.

RefCampaign processes Stripe webhooks asynchronously. Conversions appear in the dashboard within approximately 10 minutes of the webhook firing, not in real time. The processing queue retries failed deliveries up to 5 times before marking a conversion as unresolvable.

### Step 3: Track conversions manually for non-Stripe payments

If you process payments outside Stripe — via PayPal, bank transfer, or a custom billing system — use the server SDK to submit conversions directly:

```ts
import { RefCampaignServer } from '@refcampaign/sdk'
const rc = new RefCampaignServer(process.env.REFCAMPAIGN_SECRET_KEY!)

await rc.trackConversion({
  orderId: order.id,   // required — idempotence key, prevents duplicate commissions
  sessionId,
  amount: 4999,        // in cents
  currency: 'EUR',
})
```

The `orderId` field is required and acts as an idempotence key: if your backend submits the same conversion twice, RefCampaign creates only one commission record. Provide `sessionId`, `customerEmailHash`, or an `affiliateCode` independently known by your server. Without an attribution input, RefCampaign cannot identify which affiliate to credit.

### Step 4: Enable cross-device attribution with identify()

After login or signup, once you know the user's email, call `identify()` once on the client side. The browser SDK hashes the email using Web Crypto SHA-256 before transmitting anything — the raw email never leaves the browser. The hash is attached only when a consented `_rc_sid` session exists; without one, `identify()` is a no-op.

```ts
import { RefCampaignBrowser } from '@refcampaign/sdk'
// Call once after login or signup, when currentUser.email is available
RefCampaignBrowser.identify(currentUser.email)
```

`identify()` is fire-and-forget and first-write-wins: the email hash attached to the click record does not change on subsequent calls for the same session.

---

## Choosing the right setup for your Stripe integration

If you are deciding between integrating RefCampaign natively via Stripe metadata versus a third-party integration layer, start with the [Stripe affiliate tracking guide](/en/guides/stripe-affiliate-tracking), then compare architectures in the [Stripe-native affiliate software vs. integration article](/en/blog/stripe-affiliate-software-native-vs-integration). For the product-level view, the [Stripe affiliate software page](/en/stripe-affiliate-software) shows how the same metadata and webhook model maps to campaigns, commissions and payout review.

The short version: Stripe-native attribution via metadata is more reliable than any approach that depends on a separate webhook pipeline or a browser-side conversion signal, because the attribution travels inside the Stripe payment object itself rather than alongside it.

For a broader comparison of affiliate tracking platforms — including how they handle ITP, postback, and Stripe integration — see [the 2026 comparison of affiliate software](/en/blog/best-affiliate-software-2026).

---

## A complete implementation in an afternoon

The implementation described above — passive CDN script, CMP callbacks, Stripe metadata handoff, and the optional `identify()` call — can be completed in an afternoon for a standard Next.js or Node.js backend. The Stripe metadata step is critical: it carries the consented attribution into the server-side payment flow.

If your program is generating revenue but you are not confident your tracking is attributing it correctly, the [diagnostic article on affiliate tracking failures](/en/blog/affiliate-tracking-how-it-works) will help you identify which failure mode is costing you attribution.

To set up affiliate conversion tracking on RefCampaign, [start a free trial](https://app.refcampaign.com/auth/signup?locale=en) or [review the pricing plans](/en/pricing). The tracking infrastructure described in this guide is active on every plan.
