Blog · Measurement

Cross-channel attribution: what's actually knowable, and what to do about the rest

Published September 7, 2026 · 10 min read

Add up the conversions your platforms report and you will get a number larger than the conversions you had. Google Ads claims some. Meta claims some. GA4 disagrees with both. Nobody is lying; each one is answering a slightly different question, in its own window, about its own users. Cross-channel attribution is the discipline of deciding what to believe when they conflict — and the useful version of that discipline starts by admitting how much of it is unknowable.

Why the numbers never reconcile

Four independent mechanisms pull the same conversion in different directions, and they compound:

  • Every platform marks its own homework. Meta reports conversions it believes it influenced; Google Ads does the same. A customer who saw a Meta ad on Tuesday and clicked a Google ad on Thursday is a conversion in both accounts. Neither platform can see the other, so double-counting isn't a bug in their reporting — it's the boundary of what they can observe.
  • The windows differ. Attribution windows, view-through settings and modelled-conversion logic vary per platform and per account, and they're configurable. Two accounts can report the same campaign differently because someone changed a setting eight months ago.
  • Conversions get re-attributed after the fact. Meta keeps revising a day's conversions over a trailing window of roughly a week as more evidence arrives. A number you screenshotted on Monday is genuinely not the number that day now holds.
  • Different tools count different populations. A Search Console click is someone clicking a result; a GA4 session is someone landing and being tracked. They were never the same population, so it is a category error to expect them to match — and yet a great many reconciliation efforts start by trying.

None of this is fixable by choosing better software. It's a property of measuring people across systems that can't see each other.

The four approaches, and who each one is for

1. Platform-reported (which is really last-click, per platform)

What you get by default, and what most teams are quietly running on. It's fast, free and directionally fine for in-platform optimization — the bidding algorithm needs a signal, and this is that signal. It is unfit for the budget question, because summing across platforms overstates your results by exactly the amount they overlap, and that overlap is invisible from inside any one account.

2. Analytics-side modelling (GA4 and equivalents)

One tool observing all traffic, applying a single model to spread credit across touchpoints. Better than summing platform reports, because at least one system sees everything and applies one rule. The cost is opacity — the model is a black box you can't inspect, it degrades as tracking consent erodes, and it still can't see anything that never reached your site.

3. Multi-touch attribution (MTA)

Stitch user-level journeys and assign fractional credit per touchpoint. Genuinely the most informative approach when it works, and the one whose foundations weakened most in the last few years: it depends on identity resolution across devices and browsers, which consent regimes and platform privacy changes have steadily dismantled. It also has a scale floor — under a few thousand conversions a month, the path data is too sparse to say anything the noise doesn't drown out.

4. Incrementality and media mix modelling

Stop tracking individuals; measure aggregates instead. Hold out a geography, turn a channel off, or model spend against outcomes over time. This is the only family that answers the question you actually care about — what would have happened without this spend — and the only one immune to cookie loss. It's also slow, needs meaningful spend to produce readable effects, and gives you a directional answer weeks later rather than a dashboard tile today.

The uncomfortable summary: the approaches that are cheap enough to run daily can't tell you about incrementality, and the ones that can tell you about incrementality can't run daily. Any vendor promising both is selling the appearance of precision.

What's realistic below enterprise scale

Most teams reading this run four to six channels and a conversion volume that will not support MTA. For them the honest stack has three layers, and it is much smaller than the market implies:

  1. Use platform-reported numbers for in-platform decisions only — which creative, which keyword, which audience. Inside one account, one consistent rule is enough.
  2. Use one blended number for budget decisions. Total spend against total revenue, every channel in one definition. It refuses to answer "which channel deserves credit" — and that refusal is the feature, because that question isn't reliably answerable at your scale anyway. We wrote the calculation up in full in blended ROAS: one honest number across Google Ads, Meta and GA4.
  3. Test incrementality when a decision is big enough to deserve it. Not continuously — before a budget shift material enough that being wrong would hurt. Turning one channel off for two weeks tells you more than a year of model output.

Notice what's absent: a step where you pick the correct attribution model. There isn't one. There's a decision about which question you're asking, and a different tool for each.

The prerequisite everyone skips

All three layers assume something that usually isn't true yet: that spend, clicks, conversions and revenue from every channel sit in one place, under one definition, with the same date grain. Until that's true, "cross-channel attribution" is a spreadsheet someone rebuilds every Monday, and the arguments it produces are about whose export is stale rather than about where budget should go.

That's the boring, unglamorous half of the problem — and it's the half you can actually finish. TableBI exists to close it: connect each source once, and every row lands in a shared facts table where cost is cost and conversions are conversions no matter which platform reported them.

terminal
# install once, teach the agent the CLI exists
npm i -g @tablebi/cli
tablebi login
tablebi install

# one OAuth round-trip per live source
tablebi connect google_ads
tablebi connect meta_ads
tablebi connect ga4
tablebi connect gsc --site sc-domain:example.com

# anything without a live connector arrives as a labelled file
tablebi connect csv --file tiktok-export.csv --platform tiktok_ads

Once every channel is in one grain, the comparison that platform dashboards structurally cannot show you is a single query — and the gap between the two numbers below is your double-counting, quantified:

claude code → tablebi
# what each platform claims, side by side, in one definition
tablebi ask "SELECT platform,
             SUM(cost) AS spend,
             SUM(conversions) AS claimed_conv,
             cpa(SUM(cost), SUM(conversions)) AS cpa,
             roas(SUM(conversion_value), SUM(cost)) AS roas
             FROM facts
             WHERE date >= (SELECT MAX(date) FROM facts) - 28
             GROUP BY platform ORDER BY spend DESC"

# and the blended view that refuses to pick a winner
tablebi ask "SELECT roas(SUM(conversion_value), SUM(cost)) AS blended_roas,
             SUM(cost) AS total_spend
             FROM facts
             WHERE date >= (SELECT MAX(date) FROM facts) - 28"

Anchor the window to MAX(date) rather than today, because platforms finalize days late — one of several caveats that ride along with every answer in a trust block, together with how fresh each source is. An attribution debate conducted on a partial final week is not an attribution debate; it's an artefact.

Make the honest number the one everybody sees

Attribution arguments recur mostly because each participant arrives with their own export. The fix is unglamorous: one live URL, one definition, refreshed automatically, so the conversation starts from a shared number instead of re-litigating whose spreadsheet is current.

claude code → tablebi
tablebi pin --title "Cross-channel truth" \
  --widget "Spend by platform=SELECT platform, SUM(cost) AS spend FROM facts …" \
  --widget "Blended ROAS (28d)::line=SELECT date, … FROM facts …"
✓ published → https://dk.tablebi.com/d/dsh_…  (public, read-only, self-refreshing)

The dashboard stores the query, not a snapshot, so it re-runs itself as data arrives. Here's a real one, pinned exactly that way:

What this does not give you

Being explicit about the limits, since the whole subject is plagued by overclaiming:

  • It is not user-level attribution. Unifying channels at a daily grain lets you compare and blend them honestly. It does not stitch a journey across devices, and nothing at this scale reliably does.
  • It does not measure incrementality. No warehouse, however tidy, tells you what would have happened without the spend. Only a holdout or a model does, and both need designing.
  • It does not resolve the disagreement — it makes it visible. That's the actual win. Knowing your platforms collectively claim 140% of your conversions is more useful than a single confident figure that hides the same overlap.

If the blocker is that the data isn't in one place yet, the smallest marketing data warehouse that actually works covers the storage question, and Claude Code for marketing covers driving the whole loop from your agent.

FAQ

What is cross-channel attribution?

Deciding how credit for a conversion is divided among the marketing channels that touched it. It becomes a distinct problem because each platform reports only what it can see and claims the conversion for itself, so platform-reported totals overlap and cannot simply be added together.

Why don't Google Ads and Meta conversions add up to my real total?

Because a customer touched by both is counted by both, and because each platform uses its own attribution window, view-through rules and modelled-conversion logic. Meta also re-attributes conversions over a trailing window of roughly a week, so a day's figures keep changing after you first read them.

Which attribution model should a small team use?

Below a few thousand conversions a month, multi-touch models don't have enough path data to beat the noise. The practical stack is platform-reported numbers for in-platform optimization, one blended figure for budget decisions, and an occasional holdout test when a decision is big enough to justify one.

Do I need a data warehouse for cross-channel attribution?

You need every channel in one place at one date grain with one set of definitions. For marketing data measured in millions of rows rather than billions, a full warehouse stack is usually several sizes too big — a backend that normalizes each source on ingest gets you the same comparability without the pipeline to maintain.

Try it

Put every channel in one definition, then see how much they overlap.

terminal
npm i -g @tablebi/cli && tablebi install