How We Measure Campaign Revenue (First-Touch Attribution)

WarmySender uses first-touch attribution for all campaign revenue reporting on the admin dashboard.

When you click a link to WarmySender — from an ad, an email, a social post, or a referral — we record the source the very first time you arrive at the site. That first source stays with your account for 90 days, even if you leave and come back.

Concretely:

Why first-touch? It tells us which campaigns introduce customers to the product, which is what marketing budget actually paid for. Last-touch attribution rewards retargeting (which often just shows the ad to someone who already decided to buy), while first-touch rewards genuine acquisition.

How we keep this evergreen across signup paths:

All three signup paths — email magic-link, Google OAuth, and Apple OAuth — read the same first-touch ws_attrib cookie and persist the captured UTM source/medium/campaign to the user record at signup. The cookie always wins over per-click signals (OAuth state, request body, URL params), because per-click signals are latest-touch leaks by definition. If the cookie is missing (private browsing, ad blocker, old browser without cookies), we fall back to the URL parameters at click time. Attribution data is never silently overwritten on a return visit.

What's tracked:

The first-touch capture includes utm_source, utm_medium, utm_campaign, gclid (Google Ads), fbclid (Meta Ads), the original referrer URL, and the timestamp of first touch. Google Ads gclid auto-derives to (google, cpc) if no explicit UTM is set; Meta fbclid auto-derives to (facebook, paid_social).

First-touch vs paid-touch:

We also record a separate paid_utm_source/medium/campaign snapshot at the moment of first checkout. Both signals are kept on the user record:

The admin dashboard surfaces an "Attribution Health" panel showing coverage percentage, paid users without attribution, and the first-touch≠paid-touch divergence rate so we can monitor the integrity of the data over time.

Related guides in Platform

Back to all documentation | Contact support