Skip to content

Attribution

A source that brings a thousand signups and no customers is worth less than one that brings twenty signups and five customers. Attribution joins where each waitlist signup came from to who is paying you in Stripe or Lemon Squeezy.

It covers people who signed up through a Launch waitlist form, hosted page or widget. It is not page analytics: it knows nothing about visitors who never signed up, and customers who never joined your waitlist have no recorded source. There is no cookie and no browser storage, and nothing is stored about visitors. Whether your site needs a consent banner is your call, but nothing here sets or reads anything in the visitor’s browser.

The hosted page at launch.nordva.dev/waitlist/<slug> and the script-tag widget record the source automatically. From your own form, pass it with the signup; see Where signups came from.

Only the first signup for an email records a source. The referrer is stored as a hostname only, and the landing page as a path without its query string.

Tag your links so the report is useful:

https://launch.nordva.dev/waitlist/acme?utm_source=producthunt&utm_campaign=launch-day

Connect Stripe or Lemon Squeezy so Launch knows who is paying. Without it the funnel still works and paying is zero. Signups and paying customers are matched by email.

Terminal window
curl "https://api.nordva.dev/v1/attribution?group_by=referrer&period_days=90" \
-H "Authorization: Bearer nv_live_YOUR_SECRET_KEY"
{
"data": {
"group_by": "referrer",
"rows": [{
"source": "news.ycombinator.com",
"signups": 412, "confirmed": 398, "invited": 120,
"paying": 9, "ever_paid": 11, "signup_to_paying": 0.022,
"money": [{ "currency": "usd", "mrr_minor": 20100, "revenue_minor": 46300 }]
}],
"stripe": { "connected": true, "status": "active" }
}
}
group_byGroups byPlan
referrer (default)Referring site’s hostname; (direct) when noneEvery plan
utm_sourceutm_source; (none) when absentBuilder
utm_campaignutm_campaignBuilder
referral_codeThe existing signup whose referral link brought the person in. Rows include referrer_emailBuilder

period_days limits the report to signups from the last N days. Omit it for all time. Rows are ordered by paying, then signups.

paying is people with an active or past-due subscription now. ever_paid is people with at least one paid invoice. money is per currency and never converted.

“Which waitlist source produced paying customers last month, and what have those customers asked for?” The assistant calls get_attribution_report, then list_contacts filtered by that source and paying, then get_contact for their feedback.

Record spend and the report gains spend per source: the amount inside the window, cost per signup, cost per paying customer and return on spend (revenue from those signups ÷ spend). A source that cost money and brought nobody is listed too.

Terminal window
curl -X POST https://api.nordva.dev/v1/attribution/costs \
-H "Authorization: Bearer nv_live_..." \
-H "Content-Type: application/json" \
-d '{
"source_type": "utm_source",
"source": "reddit",
"period_start": "2026-09-08",
"period_end": "2026-09-14",
"amount_minor": 20000,
"currency": "usd",
"note": "Promoted post"
}'

source_type is the grouping the cost belongs to (referrer, utm_source or utm_campaign) and source is the value as it appears in the report. Amounts are in the smallest currency unit. A period that only partly overlaps the report window counts in proportion to the days that do. Spend is only ever compared with revenue in the same currency. Send up to 500 at once as { "costs": [...] }; list with GET /v1/attribution/costs; remove with DELETE /v1/attribution/costs/<id>. Costs need Indie or above. In the dashboard this is Insights → Which sources bring people who pay → Record a cost, and an AI agent can do it with add_channel_cost (“I spent $200 on Reddit last week”).

Off by default. Switch it on in Settings, or with PATCH /v1/project and { "count_views": true }, and the report gains views and view_to_signup per source, so you can see views → signups → customers.

  • Hosted waitlist and changelog pages on launch.nordva.dev are counted from that moment.
  • For a widget on your own site, add data-count-views to its script tag. Without the attribute the widget sends nothing, whatever the project setting.
  • Pages on your own custom domain (Builder) are counted the same way, from the widget Worker that serves them. A page in an iframe is not counted.

What is collected: one request per landing, carrying the referring site’s hostname and the utm_source and utm_campaign values. It is added to a daily total per source. No cookie, no browser storage, no IP address, no user agent and no visitor or session identifier is stored, so there are no unique visitors, sessions or paths, and a person who comes back tomorrow is simply counted again. Moving between pages of the same site is not counted. Obvious bots are left out. Totals are kept for two years.

This is a count, not analytics. For visits to your own site, unique visitors, goals, funnels and tracing a payment back to the first visit, add the web analytics script.