Web attribution

Optional. For products with their own marketing landing page: which first-touch visit led to a checkout.

What it is

A one-line script on your marketing site records the first visit (referrer, UTM, click ids) under a random visitor id. When that same id is passed into Stripe Checkout as client_reference_id or into Paddle Checkout as customData.ek_visitor_id, Erdi links the checkout to that first touch. Nothing is required in your product or app binary — only the marketing page and your own checkout wiring.

1. Create and embed the snippet

In the app: project Settings → API → create a token with purpose Attribution snippet, set Allowed origin to the exact marketing-site origin (scheme + host, no path, e.g. https://peeranimo.com), then paste the one-line script Erdi shows after create:

<script src="https://erdiknows.com/api/v1/attribution/ek_…" async></script>

The script stores the visitor id in localStorage under ek_vid and posts a first-touch visit once. The token is write-only for visits; it cannot write deploy events, metrics, or tickets. FAQ background: Do I have to install a script on my site?

2a. Pass the visitor id into Stripe Checkout

Erdi does not create Checkout Sessions for you. When your backend (or edge) creates a Stripe Checkout Session, set client_reference_id to the same id the snippet stored in the browser. Read it on the page that starts checkout and send it to your server with the rest of the checkout request.

In the browser (marketing or checkout page):

const visitorId = localStorage.getItem('ek_vid')
// Send visitorId to your server when starting checkout.

When creating the session (server):

const session = await stripe.checkout.sessions.create({
  mode: 'payment', // or subscription
  // …
  client_reference_id: visitorId || undefined,
})

If ek_vid is missing (direct traffic, no snippet, different browser), omit client_reference_id. The webhook still succeeds; Erdi simply writes no attribution marker.

2b. Pass the visitor id into Paddle Checkout

Erdi does not open Paddle Checkout for you. When you call Paddle.Checkout.open, put the same ek_vid in customData.ek_visitor_id. That key is required — Erdi looks for exactly ek_visitor_id on transaction.completed.

const visitorId = localStorage.getItem('ek_vid')

Paddle.Checkout.open({
  items: [/* … */],
  ...(visitorId
    ? { customData: { ek_visitor_id: visitorId } }
    : {}),
})

If ek_vid is missing, omit customData (or the key). The Paddle webhook still writes the usual payment timeline marker; Erdi simply writes no attribution marker.

3. Webhooks

Stripe: Settings → Webhooks → Stripe Checkout attribution. In Stripe, subscribe to checkout.session.completed only and paste the whsec_… signing secret. Detail: Stripe Checkout attribution.

Paddle: the existing Paddle webhook destination (same as timeline payments) is enough — no second endpoint. On transaction.completed, Erdi also reads data.custom_data.ek_visitor_id. Detail: Paddle.

4. Where results appear

In the app, open the project Acquisition tab. If an attribution snippet token is active for the project, a Web attribution section shows conversion counts for the selected range (today / yesterday / 7 / 30 / 90 / custom), broken down by first-touch utm_source or referrer. Counts are checkouts with a known first touch — not revenue.

Providers

Stripe Checkout (client_reference_id) and Paddle Billing (customData.ek_visitor_id) are both supported. Both call the same conversion helper after a matching visit.

Get started with ErdiKnows