Revenue attribution

Connect Stripe, Polar or Dodo Payments per website, and link every sale to the visit that produced it.

How it works

The script gives each visitor a first-party id (cookies datacheap_visitor_id and datacheap_session_id on your domain). When that id reaches the payment, DataBull knows which visit, source and campaign produced the sale. It gets there in one of three ways:

  1. Payment links are tagged by the script automatically. Nothing to do.
  2. Server-created checkouts: pass the two ids as metadata (examples below).
  3. Success page: when the buyer lands back on your site with the provider's checkout id in the URL, the script links it.

Each website connects its own payment account. A dedicated account can send every payment to one site (new products included), or a shared account can split by product.

Overviews for each provider: Stripe, Polar, Dodo Payments.

Stripe

  1. In the website's setup, choose Stripe and click the link to create a restricted key. The permissions are pre-filled: read access to Checkout Sessions, Charges, PaymentIntents, Invoices, Subscriptions, Products, Prices and Customers, plus write access to Webhook Endpoints.
  2. Paste the key (rk_live_…). Leave "Instant updates" on to create the webhook.
  3. Choose "Every payment in this account" or pick products.

Payment Links

Nothing to do: the script adds client_reference_id to every buy.stripe.com link on your site. Optional backup: set the link's after-payment redirect to https://yoursite.com/thanks?session_id={CHECKOUT_SESSION_ID}.

Checkout Sessions

const cookie = (name) => request.headers.get('cookie')?.match(new RegExp('(?:^|; )' + name + '=([^;]+)'))?.[1];
const metadata = {
  databull_visitor_id: cookie('datacheap_visitor_id'),
  databull_session_id: cookie('datacheap_session_id'),
};

const session = await stripe.checkout.sessions.create({
  mode: 'payment', // or 'subscription'
  line_items: [{ price: 'price_…', quantity: 1 }],
  metadata,
  subscription_data: { metadata }, // subscriptions: renewals keep the visitor
  success_url: 'https://yoursite.com/thanks?session_id={CHECKOUT_SESSION_ID}',
});

Subscriptions: the first invoice is credited to the checkout's visitor, and every renewal inherits it. Custom PaymentIntent flows work when the intent carries the same metadata.

Polar

  1. In Polar: Settings → Developers → New token, no expiration, with the scopes organizations:read products:read orders:read subscriptions:read customers:read refunds:read checkouts:read webhooks:read webhooks:write.
  2. Paste the token (polar_oat_…), choose Production or Sandbox, keep "Instant updates" on.
  3. Choose every payment or specific products.

Checkout links

Nothing to do: the script adds reference_id to every buy.polar.sh link, and Polar copies it onto the order. Optional backup: success URL https://yoursite.com/thanks?checkout_id={CHECKOUT_ID}.

Checkout API

const checkout = await polar.checkouts.create({
  products: ['<product id>'],
  metadata, // same two ids as above
  successUrl: 'https://yoursite.com/thanks?checkout_id={CHECKOUT_ID}',
});

Dodo Payments

  1. Dodo → Developer → API keys: create a key and paste it (Live or Test).
  2. Pick this website's products. One key covers the whole business; other sites can use the same connection with different products.

Payment links (/buy/pdt_…) are tagged automatically. For checkout sessions, pass the same metadata object, and set return_url to a page on your site.

Switching from DataFast

Checkout metadata named datafast_visitor_id / datafast_session_id is read too, so existing checkout code keeps working.

Weighing the two up? See DataBull vs DataFast.

Revenue is shown in USD, excluding tax. Other currencies are converted at the day's exchange rate.