Documentation
Concepts

Attribution

How each payment gets the channel that introduced the customer and the one that closed them.

Every payment gets two answers, not one:

  • Introduced by — the earliest qualifying touch inside the window. This is who found the customer.
  • Closed by — the latest qualifying touch before the money. This is who finished the job.

A blog post that brought someone in six weeks ago and an ad they clicked yesterday both did work. One number would hide one of them.

What counts as a touch

A touch is a human $session_start, $pageview, or $screen that carries a real source: a channel other than direct or internal, or a click ID.

  • A visit with no campaign and no referrer is not a qualifying touch.
  • A move from one page of your own site to another is not a touch.
  • Bot visits never count. See Bot traffic policy.
  • If no qualifying touch exists in the window, the payment is Direct. FounderHQ never promotes a random visit to fill the gap, and Direct never erases a known earlier source.
  • A payment with no known buyer is not Direct. It shows as Not linked to a visit. So does a payment imported from before you installed FounderHQ, and one whose window reaches past the events your plan keeps.

The window

The window is counted back from the day the money was earned, not the day the webhook arrived. That keeps a renewal on the renewal's own merits. The default is 90 days. You can also use 30, 60, or 180. Each result records the model and the window that produced it, so two reports never disagree silently.

Where the source comes from

The SDK reads campaign parameters and ad click IDs from the URL on every landing, then keeps both the first and the latest value on the contact. There are 24 keys: the five utm_* parameters plus 19 click IDs from Google, Meta, Microsoft, LinkedIn, TikTok, Reddit, and others. The full list is in the event taxonomy. Mobile deep links and the Play install referrer feed the same keys.

Keep the chain through checkout

The gap most products lose is checkout. Attach the visitor's IDs to the payment so the payment can find the person.

const metadata = founderhq.checkoutMetadata();
// pass metadata into your Stripe or Dodo checkout session

Renewals do not carry that metadata, so FounderHQ also remembers the provider customer once matched. See Checkout metadata and payment links.

If a payment cannot be matched to anyone, FounderHQ does not guess. The payment still counts in your revenue, and it shows as Not linked to a visit in the channel breakdown.

When facts arrive late

A touch that shows up after a decision was made does not quietly rewrite history. FounderHQ recomputes the decision when the payment's buyer changes or when you change the attribution window, and the new answer is added as a new version, so a number you screenshotted last week still explains itself.

AI agent or LLM? Read this page as markdown

On this page