Tracking & Attribution

How Do You Read an Attribution Report Honestly?

An attribution report is a set of arguments, not facts. Read the model, the window and the identity layer before you trust a single row of it.

Quick answer

An attribution report is a set of arguments, not a set of facts. Every number in it is the output of a rule that decided which touch in a customer's journey deserved the credit, applied to whatever journeys the tool was able to see. Read it by asking three things of every row: which model produced it, what window it covers, and whether the tool could stitch a person's sessions together at all. A report that does not state its model and window is not a report, it is a number. And the identity layer underneath decides whether any of the models above it mean anything.

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

An attribution report is a set of arguments, not a set of facts. Every number in it is the output of a rule that decided which touch in a journey deserved the credit, applied to whatever journeys the tool was able to see.

So read it by asking three things of every row: which model produced it, what window it covers, and whether the tool could stitch one person’s sessions together at all.

Attribution reports rarely mislead on purpose. They mislead because a single number gets presented as the answer to a question nobody ever specified.


What is an attribution report actually telling you?

That a set of conversions happened, and that a rule assigned each one to a channel. The conversions are observed. The assignment is a choice. An attribution model is that choice written down — which touch in the journey gets the credit — and changing the rule moves every row in the table without a single sale changing.

Three things make up any report, and you need all three before a number means anything:

  • The population. Which conversions were counted. A report counting form submissions and one counting paid invoices are not comparable, and both will call their column “conversions”.
  • The window. How far back it looked for a touch to credit. A short window and a long one over the same journeys produce different winners, because only the long one sees the click that started things.
  • The rule. Which touch in that window gets the credit — first, last, or some distribution across the middle.

A report that leaves any of the three implicit is asking you to trust its defaults: usually last-click, inside whatever window the tool shipped with, over the journeys it happened to stitch. Defensible choices — but not the truth, and not the choices your ad platform made.


Why do first-touch and last-touch disagree?

Because they answer different questions, and both answers are correct. First touch asks what introduced this customer. Last touch asks what closed them. A channel that creates demand and a channel that harvests it look completely different depending on which question you ask, and neither model is lying when they disagree.

The textbook shape: a cold paid social ad introduces someone who was not looking for you. Days later they search your brand name and buy. Last touch hands the sale to branded search, which now looks like your most efficient channel by a mile. Cut the paid social budget and branded search quietly dries up a month later.

First touch has the mirror-image failure: full credit to a top-of-funnel channel that introduces thousands of people who never convert, while the email that actually closed the sale shows nothing.

Dark dashboard mockup comparing three attribution models side by side — First Touch, Last Touch and Resolved — each as a card showing its own purchase count and a per-channel percentage split, with the resolved model showing more purchases than the other two

The takeaway is a diagnostic rather than a preference: the gap between the two models is the information. If first touch and last touch return the same picture across every channel, either your customers genuinely buy on a single touch — rare outside cheap impulse categories — or your tool is not connecting sessions into people, so every journey it sees is one session long.

The second case is far more common, and it is invisible unless you go looking. A single-touch report is not evidence that your customers are simple. It is usually evidence that your measurement is.

When the models do disagree, that disagreement is the input to the decision, not a problem to be solved by picking a favourite. Deciding which channel to scale is a question about what happens when you move budget, and one model cannot answer it alone.


Why doesn’t the assisted column add up to your total revenue?

Because assists are counted at full credit, once per assisting channel, rather than split into fractions. One order that touched three channels can appear as the full order value in three separate assist rows. That is deliberate, and it is why the assist table almost always carries a footnote saying it does not sum to the total.

The distinction to hold onto: the conversion table measures ownership, the assist table measures involvement. Different units — adding one to the other produces a number that corresponds to nothing.

What assists are good for is finding the channels last-touch reporting buries. A channel with a high share of assists and a low share of closes is in the path repeatedly and never gets the final click; cutting it because its attributed revenue looks small is the most common self-inflicted wound in paid media. Read the assist column as a ranking, never as a sum.


Why does your report disagree with your ad platform’s numbers?

Because the platform is reporting a different population, over a different window, under a different rule — and it can only count conversions it managed to match to a person it recognises. Four structural causes, none of them a bug:

Different windows. Each platform credits conversions inside its own attribution window, and the defaults differ between platforms. Two platforms can each legitimately claim the same sale.

View-through credit. Ad platforms may credit an impression that was never clicked. Your own report, built from your own site’s data, never saw that impression — which alone accounts for a large gap on upper-funnel campaigns.

Matching. An event the platform receives but cannot resolve to a user sits in its delivery numbers and not its attribution numbers. When you send conversions server-side through the Conversions API, how complete the identifier set is on each event is what the platform scores as event match quality — and an unmatched event is credited to no click, because the platform does not know whose click it was.

Deduplication. The same conversion can reach a platform twice, once from the browser and once from your server. Meta deduplicates those when both copies carry the same event name and the same event ID; when they do not, one sale is counted as two — and unevenly across channels.

Every ad platform is grading its own homework. That does not make its report worthless — it is the only view that includes impressions and the platform’s own identity graph — but it does make it unsuitable for comparing platforms against each other. Only your own report applies one rule to all of them.


What makes “Direct” the most misleading row in a report?

Direct is not a channel. It is the label a report puts on sessions where it could not work out a source. Read as traffic, it flatters you — all those people typing your domain from memory. Read correctly, it is the report’s own blind-spot meter, and it grows precisely when your tracking breaks.

What fills the bucket is almost all measurement failure rather than customer behaviour: blocked scripts, iframe-embedded forms, expired cookies, a journey split across two devices. The most common case of all is a conversion session that arrives bare because the visitor came back by typing the domain an hour after the ad click — which is why ad conversions show up as Direct far more often than any media buyer’s instinct says they should.

Two habits follow. Track Direct as a share over time, not an absolute — a step change after a site migration or a consent-banner change is a tracking regression, and anyone looking at one week will misread it as consumer behaviour. And treat a large Direct bucket as a ceiling on what any model in the report can tell you: you cannot model your way out of missing data.


What should you check before you trust a report?

Six things, in this order: the model, the window, the timezone, the currency, the deduplication and the identity layer. The first five you can read off the report header in a minute. The sixth decides whether anything above it is true.

  1. The model. Named on the report, or the report is unusable. If you cannot find it stated anywhere, assume last-click.
  2. The window. Compare like with like. Changing the window between two exports and calling the difference a trend is the easiest mistake here to make by accident.
  3. The timezone. Daily totals that disagree with an ad platform slightly, every day, in the same direction are a day-boundary problem, not a tracking problem.
  4. The currency. Mixed-currency revenue has to be normalised to something. Ask what rate, as of when — a report that silently converts at today’s rate restates last quarter every time you open it.
  5. The deduplication. One conversion, one row, no matter how many systems reported it. Webhooks get redelivered and pixels double-fire; if the report cannot show you it is idempotent, assume it is not.
  6. The identity layer. Whether the tool believes two sessions belong to the same human. If it does not, every model collapses to “last session” regardless of what the model selector says.

The first five you can fix with a settings change and some discipline. The sixth you cannot fix from a spreadsheet, and it does the most damage because it degrades silently — there is no error message for a report that quietly stopped connecting people.

It also has a floor no configuration moves: a report can only resolve people who identified themselves somewhere. Someone who typed an email into your form and left without submitting is an identifiable person — a partial lead — but only if something captured that field before the page closed. If nothing did, there is nothing to join on later, and their purchase lands in Direct forever.


How does PartialLeads report attribution?

By showing the disagreement rather than hiding it. The Attribution report puts three models side by side — First Touch, Last Touch, and PartialLeads Resolved — each with its own purchase count and its own per-channel split. The resolved model can show a higher purchase count than the other two, because it recovers purchases a raw first- or last-click view loses entirely.

Above them sits a KPI strip: attributed revenue, attributed purchases, time to purchase as median and average, match rate, and recovered revenue — each compared against the prior period. Period, timezone and currency are explicit selectors rather than buried defaults, and multi-currency revenue carries a footnote naming the rate source and date. The display layer resolves on last-non-direct with a 28-day decay window, chosen to line up with the window advertisers already read in their ad platform.

The part that answers the Direct problem is Recovered Attribution, itemised by mechanism rather than given as one lump: first touch re-linked to a lost ad click; sessions with no campaign parameters reclassified to a real channel by the session classifier, with per-channel counts; and revenue from matched buyers whose session never finished a form. The reclassified bucket is typically the largest — traffic that would otherwise have read as Direct.

Dark dashboard mockup of a Recovered Attribution panel itemised by three mechanisms — iOS ad-click rescue, reclassified by session intelligence, and partial-lead revenue — above a channels table with revenue, purchases, average lag and ROAS columns

The Channels table carries a First / Last / Resolved toggle, so the ranking moves under each rule in front of you; paid channels expand to their campaigns, with average lag, visitor-to-lead rate and ROAS columns. Conversion Paths & Assists shows path sequences with counts, a touches-per-purchase distribution and a days-to-purchase distribution, plus an assisting-channels table labelled explicitly as full-credit and not summing to the total. Time to Purchase plots the first-touch series against the last-touch series, keeping journey length and decision length separable. And Revenue by Match Quality splits net revenue into partial-captured, submit-completed and unmatched.

What breaks The mechanism Where you see it in the dashboard
One number presented as the answer First, Last and Resolved models rendered side by side Attribution report, model cards
Conversions that lose their source entirely Resolved model over the identity cluster, own purchase count Resolved model card vs first/last
Sessions with no campaign parameters read as Direct Session classifier reclassification, itemised per channel Recovered Attribution, reclassified bucket
A sale weeks after the ad click First touch stored on the person, not the session Time to Purchase, first vs last series
Assisting channels buried by last-click Conversion paths and assisting-channels table Conversion Paths & Assists
Buyers whose form was never submitted Partial capture before submit, matched to the purchase Revenue by Match Quality, partial-captured wedge
Reports that disagree with the ad platform Explicit period, timezone and currency selectors Report header chips, ECB rate footnote
Refunds inflating attributed revenue Refund rows netted against paid Purchases ledger, net revenue
A redelivered webhook counted twice Deterministic event ID with unique dedup tables CAPI activity log, one row per event

The honest constraints, because a report that hides its own limits is the thing this article argues against. The resolved model is built from deterministic joins and bounded inheritance, not probabilistic modelling — it will not invent a source where no identifier existed. Conversion metrics can show a “warming up” state while visitor figures are still computing, rather than a confident wrong number. The assisting-channels table does not sum to the total, by design. And PartialLeads controls what gets dispatched to an ad platform and how complete it is, never whether that platform can resolve the person to an account — that depends on its graph, consent and opt-out status. No vendor owns that half.

Tell us what's broken. We'll fix your tracking — free.

Describe the tracking/attribution problem you're stuck on and we'll map it to a fix: server-side conversions to Meta, Google, TikTok and Pinterest, plus first-party tracking that survives Safari. No code required.

Sources

  1. Meta for Developers — Conversions API overview: https://developers.facebook.com/docs/marketing-api/conversions-api
  2. Meta for Developers — Deduplicate Pixel and Conversions API events: https://developers.facebook.com/docs/marketing-api/conversions-api/deduplicate-pixel-and-server-events
  3. Meta for Developers — Conversions API best practices: https://developers.facebook.com/docs/marketing-api/conversions-api/best-practices

Frequently asked questions

QWhich attribution model should I actually use?
For budget decisions, read first touch and last touch together and treat the gap between them as the finding. For platform comparisons, use whichever single model you apply consistently to every channel. There is no correct model, only a model whose question matches the decision you are about to make — and a model chosen after seeing the numbers is a rationalisation, not a method.
QWhy does my ad platform report more conversions than my own dashboard?
Usually four reasons stacked: a longer or different attribution window, view-through credit for impressions your own site never saw, and deduplication gaps where one sale reached the platform from both the browser and your server. The reverse gap — your dashboard showing more — usually means the platform could not match some of the events it received to a user.
QIs assisted revenue real revenue?
The revenue is real; the column is not additive. Each assisting channel is credited the full order value, so one order can appear at full value in several assist rows. Use the assist table to rank which channels are repeatedly in the path without closing. Never add assisted revenue to attributed revenue — the result describes nothing.
QWhat does a high Direct percentage mean?
Almost always that sessions are not being connected to a source, not that people are typing your domain. Blocked scripts, iframe-embedded forms, expired cookies and device switching all land in Direct. Track it as a share over time: a step change after a site, checkout or consent change is a tracking regression, and it caps how much any model in the report can tell you.
QCan an attribution report show more conversions under one model than another?
Yes, if the models run over different populations. A model that resolves sessions into people can credit a purchase that a raw first- or last-click view drops entirely for having no identifiable source. The models are not redistributing a fixed pool of conversions; they can each see a different number of them.
QHow long an attribution window should I use?
Long enough to contain your actual sales cycle, which you can read off a days-to-purchase distribution rather than guess. The risk of a short window is systematically under-crediting channels that introduce people early. The risk of a long one is crediting touches that had nothing to do with the sale. Pick one, state it, and stop changing it between exports.
QWhy do my daily numbers disagree with my ad platform's by a small amount every day?
Check the timezone before anything else. Two systems bucketing the same events into days on different boundaries will disagree consistently, in the same direction, without either being wrong. A difference that is small, stable and always in one direction is a boundary artefact; a difference that is large or erratic is a tracking problem.
QDoes multi-touch attribution fix any of this?
It changes the rule, not the inputs. Spreading credit across touches is still arithmetic performed on whatever journeys the tool managed to observe, so a multi-touch model built on unstitched sessions is a more elaborate way of reporting last session. Fix the identity layer first; the choice of model is the smaller decision of the two.

Find the qualified leads your forms are currently throwing away.

Install PartialLeads on one landing page, send traffic, and compare what your CRM captured against what PartialLeads recovered and qualified.