Make the data reliable
Tracking, attribution and sources: what you can trust before analyzing anything.
Decide which numbers you can believe before you analyze any of them. Bad attribution produces confident recommendations aimed at the wrong channel, and the team then spends months carrying them out.
This chapter ends with a reliability sheet: every metric the audit relies on, its source, and a status of trust, use with care or do not use. As an illustration, take a B2B SaaS at 2M ARR with a free trial and a blog that gets most of its traffic. Its dashboards say brand search and direct bring most signups, and the blog brings almost none.
Reconcile the sources before reading any of them
Pull the same metric for the same period from every system that holds it. Agree on the source of truth first, then explain the gap.
| Metric | Source of truth | Compare with | What a gap usually means |
|---|---|---|---|
| Signups | Product database | Web analytics conversion event | Consent refusals, ad blockers, an event firing twice, invited users |
| New customers | Billing | CRM closed-won | Deals never invoiced, self-serve customers missing from the CRM |
| New ARR | Billing | CRM amounts, board deck | Discounts, annual and monthly mixed, taxes included |
| Churn | Billing | Customer success tool, board deck | Downgrades and pauses counted differently |
| Ad spend | Accounting | Ad platforms | Agency fees and tools left out of CAC |
| Organic visits | Search Console clicks | Web analytics sessions | Two different units, plus consent |
A stable gap is usable, since you can still read the trend. A gap that moves from month to month means the trend itself can’t be trusted, and that metric gets a do not use until someone explains it.
See what a last-click model hides
Here is one illustrative path through that SaaS:
| Day | Touch | Page | Credit in last click |
|---|---|---|---|
| 1 | Google, generic query | Blog post | None |
| 9 | LinkedIn post | Home | None |
| 20 | Google, brand name | Pricing, then signup | 100% brand |
Brand search is where convinced people go, so a last-click model flatters brand and hides the origin of the conversion. The danger comes at budget time: the blog looks useless and the brand looks like a growth engine, when the brand query only exists because of the earlier touches.
GA4 gives you data-driven and last-click attribution, and the position-based models were removed in 2023, so any other model has to be computed outside it. A cheap cross-check is a free-text “how did you hear about us?” field at signup or in the first sales call. Compare what people declare with what your tools recorded, and pay attention to the channels where the two diverge most.
Find the links that carry no information
On an audit I ran for a B2B SaaS, blog calls to action, menus and alerts went untagged, and that alone distorted the reading of every channel. Walk through each place a visitor can click toward signup and fill this in.
| Link location | Typical state | Effect | Fix |
|---|---|---|---|
| Blog CTA, inline or end of post | No tracking | Blog signups look like direct | cta_click event, plus UTMs if the signup app is separate |
| Main menu and footer | No tracking | Impossible to tell whether navigation converts | cta_click event |
| Newsletter and email sequences | Sometimes tagged | Email merges into direct | UTMs on every link |
| Product alerts and notifications | Rarely tagged | Returning users look like new direct visits | UTMs with a dedicated source |
| Partner and social links | Inconsistent naming | One source split into five | Written naming convention |
# Coming from outside, or handing over to a separate signup app
?utm_source=newsletter&utm_medium=email&utm_campaign=2026-11-benchmark
?utm_source=alert&utm_medium=email&utm_campaign=weekly-report
?utm_source=blog&utm_medium=cta&utm_campaign=guide-cold-email&utm_content=bottom
# Between two pages of the same site: no UTM, send an event
event: cta_click
params: cta_location, cta_text, page_path, destination
The second block matters. In web analytics, a UTM on a link between two pages of the same site restarts attribution and overwrites the real source. Use UTMs for traffic from outside and for handovers to a separate app that reads them at signup, and use events inside the site.
Then measure how much you are blind to. If your users table stores the source captured at signup:
SELECT
DATE_TRUNC('month', created_at) AS month,
COUNT(*) AS signups,
ROUND(100.0 * COUNT(*) FILTER (WHERE utm_source IS NULL) / COUNT(*), 1) AS pct_no_utm
FROM users
WHERE created_at >= CURRENT_DATE - INTERVAL '12 months'
GROUP BY 1
ORDER BY 1;
Read the attribution logic line by line
Most homemade attribution is a list of ordered conditions, in a CRM workflow, a spreadsheet or a SQL view. Ask for it, because it stops at the first source found, and so the order of the conditions decides the result.
CASE
WHEN utm_source IS NOT NULL THEN utm_source
WHEN referrer ILIKE '%google.%' THEN 'organic_search'
WHEN landing_page LIKE '/blog/%' THEN 'blog'
ELSE 'direct'
END AS acquisition_source
A visitor who arrives from Google on a blog post gets organic_search, and the third rule never runs. Move the blog condition above the referrer condition and the same visitor becomes blog. A paid Google click that lost its UTM and lands on a product page ends up in organic_search under both versions.
Run the rule set on the last twelve months of signups, swap the order of the two conditions that overlap most, and compare the distributions. If the channel ranking changes, every past decision based on that ranking deserves a second look. Then write the agreed order down in a place the team can find.
Ask each tool only what it can answer
A product analytics tool is built to describe what users do once they are inside, and it should not be your acquisition reference.
| Tool | Reliable for | Do not ask it |
|---|---|---|
| Product analytics | Activation, feature usage, retention | Where visitors came from before they had an account |
| Web analytics | Traffic, landing pages, on-site paths | Revenue, qualified leads |
| Search Console | Queries, impressions, position, click-through rate | Conversions |
| CRM | Pipeline and deals | Original source, unless it is filled automatically |
| Billing | What was actually paid | Where the customer came from |
| Ad platforms | Spend and delivery | Credit for conversions, since each platform counts its own |
Deliver a quick fix and an advanced one
The quick fix fits in the first weeks of the roadmap: track the blog’s CTAs and the navigation, tag emails and alerts, add an acquisition analytics tool that captures the first and last source of each visitor and passes both to the signup, and write down the attribution order.
The advanced fix is multi-touch. Store every touch per account, then split the credit, for example 40% to the first touch, 40% to the last and 20% shared between the ones in the middle. Assuming a touches table with one row per visit and the account’s conversion date:
WITH ordered AS (
SELECT
account_id,
channel,
ROW_NUMBER() OVER (PARTITION BY account_id ORDER BY touched_at) AS n,
COUNT(*) OVER (PARTITION BY account_id) AS total
FROM touches
WHERE touched_at <= converted_at
),
weighted AS (
SELECT
channel,
CASE
WHEN total = 1 THEN 1.0
WHEN total = 2 THEN 0.5
WHEN n = 1 OR n = total THEN 0.4
ELSE 0.2 / (total - 2)
END AS credit
FROM ordered
)
SELECT channel, ROUND(SUM(credit), 1) AS attributed_conversions
FROM weighted
GROUP BY channel
ORDER BY attributed_conversions DESC;
The weights are a convention. Their use is to put the channels that open a journey next to the ones that close it, so read this model beside last click. Run it on qualified leads and customers as well as on signups, because the ranking often changes.
What to deliver: the reliability sheet
| Metric | Source | Status | Issue | Fix | Owner |
|---|---|---|---|---|---|
| Signups by source | Product database | Use with care | Blog CTAs untagged, blog undercounted | Quick fix on CTAs | Marketing |
| New ARR | Billing | Trust | Reconciled with finance | None | Finance |
| CAC by channel | Spreadsheet | Do not use | Last click, agency fees missing | Rebuild after tracking | Growth |
A finding reads like this: “The blog is reported as a marginal source because its CTAs carry no tracking and the model is last click. Until this is fixed, no conclusion on content budget holds.” The channel-level work in the acquisition chapter and the stage rates in the funnel chapter both start from this sheet. For organic performance, the tracking chapter of the programmatic SEO guide goes further.
Your next step: export the last twelve months of signups, compute the share without a source, and ask whoever built your attribution for the exact list of conditions in their order.