# Revenue attribution

> Connect a payment processor so each payment is matched to the visit that brought it, using the atrby_sid visit id from checkout and signed webhooks.

Canonical: https://atrby.site/docs/revenue
Last updated: 2026-10-21

Connect your processor and every payment is matched to the visit that brought it.

## How matching works

1. The script gives each visit an id, `atrby_sid`. You read it at checkout with `atrby.ids()`.
2. You put it in the checkout's metadata. Your processor keeps it on the payment.
3. Your processor sends atrby a signed webhook. atrby reads the id, finds the visit and credits its source, landing page and campaign.

## 1. Connect the processor

In the app, open Revenue → Payment processors → Connect. Paste the webhook signing secret from your processor. atrby shows the webhook URL to add and the events to send. Secrets are stored encrypted, and every webhook is checked against its signature.

- [Stripe](https://atrby.site/docs/integrations/stripe): Webhook, metadata and renewals.
- [Lemon Squeezy](https://atrby.site/docs/integrations/lemon-squeezy): Webhook and checkout custom data.
- [Polar](https://atrby.site/docs/integrations/polar): Webhook and checkout metadata.
- [Paddle](https://atrby.site/docs/integrations/paddle): Notification destination and custom data.
- [Dodo Payments](https://atrby.site/docs/integrations/dodo): Webhook and payment metadata.
- [Shopify](https://atrby.site/docs/integrations/shopify): Order webhook and cart attributes.

## 2. Pass the visit ids at checkout

Read the ids in the browser, send them with your checkout request, and put them in the processor's metadata on your server.

*Browser*

```js
const ids = window.atrby?.ids(); // { atrby_sid, atrby_site }
await fetch("/api/checkout", { method: "POST", body: JSON.stringify({ plan, ids }) });
```

*Server · Stripe*

```js
await stripe.checkout.sessions.create({
  // ...line items
  metadata: ids,
  subscription_data: { metadata: ids }, // renewals attribute too
});
```

## 3. Identify at sign-up (recommended)

People often pay days after their first visit. Call `atrby.identify(user.id)` at sign-up and add `atrby_uid: user.id` to the same metadata. See [identify users](https://atrby.site/docs/identify).

## What you get

- Revenue, customers and refunds by channel and source, with the previous period.
- Revenue by entry page and campaign in the Overview breakdowns.
- A list of payments with the source of each, exportable as CSV from the Revenue screen.

**Retries and duplicates are safe.** Each payment is stored once per processor and id, so webhook retries never double count. Refunds are subtracted from the source of the original payment.

Payments with neither id, or with ids we can't find, are still counted and labelled Unattributed. We never guess. Amounts are summed in their own currency; there's no currency conversion yet, so use one currency per site for clean totals.

## Not on a supported processor?

Send payments from your server with the [Payment API](https://atrby.site/docs/payment-api).

## Related
- [Identify users](https://atrby.site/docs/identify)
- [Events and goals](https://atrby.site/docs/events)
- [Script reference](https://atrby.site/docs/tracker)
