# Agree on the Number of Sales Before You Argue About Credit

Every platform claims credit for the same conversions, so your channel debate is built on a number nobody agreed on. Fix the count first: dedupe and identity resolution before attribution models.

- Canonical: https://mbuzz.co/articles/count-conversions-before-crediting-channels
- Published: 2026-07-23
- Author: Holly Mehakovic, mbuzz (https://mbuzz.co)

---

> **TL;DR:** When every platform claims credit for the same conversions, the problem is not which model to use. It is that you never agreed on how many conversions there were. Google claims 300, Meta claims 250, but Shopify recorded 320 actual orders. The counting problem comes before the credit problem. Fix it in order: deduplicate conversions to one number, resolve identity across devices and channels, then run attribution. Attribution models distribute credit for a total. If the total is wrong, every model is wrong, no matter how sophisticated.


## The Argument You Can't Win

Here is a meeting that happens every month, in every marketing team spending real money.

Someone pulls up the dashboards. Google Ads says it drove 300 conversions. Meta says 250. Email says 120. The performance lead argues Google deserves more budget. The brand lead argues Meta is being undercredited. Everyone has a model in mind, and everyone's model happens to favour the channel they own.

The argument runs for forty minutes and resolves nothing, because it was built on a foundation nobody checked. Add those numbers up:

<div class="not-prose my-8 bg-white border border-slate-200 rounded-lg overflow-hidden">
  <div class="px-5 py-3 border-b border-slate-200 bg-slate-50">
    <p class="text-xs font-bold text-slate-500 tracking-[0.15em]">CLAIMED vs ACTUAL, ONE MONTH</p>
  </div>
  <div class="px-5 py-5">
    <div class="grid grid-cols-2 gap-3">
      <div class="bg-slate-50 border border-slate-200 rounded-md p-4">
        <div class="text-[10px] font-bold tracking-[0.15em] text-slate-500 mb-3">CONVERSIONS CLAIMED</div>
        <ul class="text-sm text-slate-700 space-y-2">
          <li class="flex justify-between"><span>Google Ads</span><span class="font-semibold text-slate-900">300</span></li>
          <li class="flex justify-between"><span>Meta Ads</span><span class="font-semibold text-slate-900">250</span></li>
          <li class="flex justify-between"><span>Email</span><span class="font-semibold text-slate-900">120</span></li>
          <li class="flex justify-between"><span>Organic</span><span class="font-semibold text-slate-900">90</span></li>
          <li class="flex justify-between border-t border-slate-300 pt-2 mt-2"><span class="font-semibold text-slate-900">Total claimed</span><span class="font-bold text-slate-900">760</span></li>
        </ul>
      </div>
      <div class="bg-emerald-50 border border-emerald-200 rounded-md p-4 flex flex-col justify-center">
        <div class="text-[10px] font-bold tracking-[0.15em] text-emerald-700 mb-1">SHOPIFY ACTUAL ORDERS</div>
        <div class="text-4xl font-bold text-emerald-700 mb-1">320</div>
        <div class="text-xs text-emerald-700">the only number that recorded real money</div>
      </div>
    </div>
  </div>
</div>

The channels claim 760 conversions for a month that produced 320 orders. Before anyone can argue about who deserves credit, there is a prior question nobody asked: **how many conversions were there?**

You cannot distribute credit for a number you haven't agreed on. And you haven't agreed on it.

## The Counting Problem Comes Before the Credit Problem

There are two separate jobs hiding inside the phrase "marketing attribution," and the industry talks about them as if they were one.

| Job | Question it answers | What it produces |
|---|---|---|
| **Counting** | How many conversions were there, really? | One deduplicated total |
| **Crediting** | How should that total be split across channels? | A per-channel share |

Attribution models (first-touch, last-touch, linear, time-decay, Markov, Shapley) are all crediting tools. Every one of them takes a set of conversions as input and distributes credit across the touchpoints on each journey. **None of them decides how many conversions there were.** They assume that's already settled.

So when every platform claims credit for the same conversions, reaching for a better model is fixing the wrong layer. A Shapley model applied to double-counted data will carefully, defensibly, mathematically distribute credit for conversions that never happened twice. The sophistication is real. The input is wrong. Garbage in, Shapley out.

The order is not negotiable:

<div class="not-prose my-8 flex flex-wrap items-stretch gap-2">
  <div class="flex-1 min-w-[150px] bg-indigo-50 border border-indigo-200 rounded-lg p-3">
    <div class="text-[10px] font-bold tracking-[0.15em] text-indigo-500 mb-1">1 &middot; COUNT</div>
    <div class="text-sm font-semibold text-slate-900">Deduplicate</div>
    <div class="text-xs text-slate-500 mt-1">to one conversion total</div>
  </div>
  <div class="flex items-center text-slate-300 text-xl">&rarr;</div>
  <div class="flex-1 min-w-[150px] bg-indigo-50 border border-indigo-200 rounded-lg p-3">
    <div class="text-[10px] font-bold tracking-[0.15em] text-indigo-500 mb-1">2 &middot; RESOLVE</div>
    <div class="text-sm font-semibold text-slate-900">Stitch touchpoints</div>
    <div class="text-xs text-slate-500 mt-1">to the right person</div>
  </div>
  <div class="flex items-center text-slate-300 text-xl">&rarr;</div>
  <div class="flex-1 min-w-[150px] bg-emerald-50 border border-emerald-200 rounded-lg p-3">
    <div class="text-[10px] font-bold tracking-[0.15em] text-emerald-600 mb-1">3 &middot; CREDIT</div>
    <div class="text-sm font-semibold text-slate-900">Run attribution</div>
    <div class="text-xs text-slate-500 mt-1">on the clean total</div>
  </div>
</div>

Most teams start at step 3 because that's where the tools and the arguments live. The leverage is at steps 1 and 2.

## Why the Count Inflates

Three mechanics push the claimed total above the real one. They are the same mechanics that make platform reports disagree, seen from the counting angle instead of the crediting angle.

### 1. Overlapping claims

Each platform claims any conversion that falls inside its own attribution window, and those windows overlap. A buyer who touches Google on day 1 and Meta on day 15 before converting on day 20 is claimed by both. Google claims it under its 30-day click window, Meta under its 7-day one. One order, two claims. Neither platform is wrong under its own rules. But you can't sum rules that overlap.

### 2. View-through and modeled conversions

Platforms don't only count clicks. Meta counts conversions from people who merely saw an ad. Google and Meta both add "modeled" conversions, estimates of activity they couldn't directly observe, filled in by their own algorithms, conveniently on their own side of the ledger. These never appeared in your order table. They're in the claimed count anyway.

### 3. Fragmented identity

This one inflates the count even inside a single honest system. One buyer researches on their phone, then converts on their laptop. With no shared identity key, that's two visitors with two separate journeys and, depending on your setup, two counted conversions for one person. Cross-device buyers get counted more than once, and their journeys get chopped into fragments that attribution then mis-credits.

The first two make platforms over-claim against each other. The third makes even your own analytics over-count. All three land in the same place: a claimed total that's larger than reality, usually by 40 to 90 percent.

## Start From the Transaction, Not the Ad

The fix begins by choosing the right source of truth for the count. There is a clean rule:

> **Count from the system that owns the money. Credit from the system that sees the journey.**

Your Shopify, Stripe, WooCommerce, or CRM order table is the real conversion count. It records actual money changing hands, once per transaction. It has no incentive to inflate, because it isn't selling you ads. That number, 320 orders, is your denominator.

Everything the ad platforms report is a claim about that denominator, not an addition to it. Google didn't create 300 conversions on top of your 320 orders. Google is claiming credit for some subset of those same 320.

<div class="not-prose my-8 grid grid-cols-1 md:grid-cols-2 gap-3">
  <div class="bg-pink-50 border border-pink-200 rounded-lg p-4">
    <div class="text-[10px] font-bold tracking-[0.15em] text-pink-600 mb-2">&times; WRONG MENTAL MODEL</div>
    <p class="text-sm text-slate-700">Google's 300 + Meta's 250 + Email's 120 = a lot of conversions.</p>
  </div>
  <div class="bg-emerald-50 border border-emerald-200 rounded-lg p-4">
    <div class="text-[10px] font-bold tracking-[0.15em] text-emerald-700 mb-2">&#10003; RIGHT MENTAL MODEL</div>
    <p class="text-sm text-slate-700">There were 320 orders. Google touched some. Meta touched some. Many were touched by both. The job is to split 320, not to sum 760.</p>
  </div>
</div>

Once the denominator is fixed at 320, the argument in the meeting changes shape entirely. It stops being "whose number is bigger" and becomes "how do we split 320", which is a question a model can actually answer.

## Resolve Identity, or the Count Stays Broken

Fixing the denominator with a clean order count solves overlapping platform claims. It does not, on its own, solve identity fragmentation. For that you need to stitch events from the same person together.

Identity resolution joins touchpoints on a shared key so one person's journey stays one journey:

| Key | How it stitches | Strength |
|---|---|---|
| **Logged-in user ID** | Same account across devices and sessions | Strongest, if you have logins |
| **Hashed email** | Same person across email, checkout, and forms | Strong, survives device changes |
| **Hashed phone** | Same person across calls, SMS, and checkout | Strong for phone-heavy funnels |
| **First-party cookie / device ID** | Same browser over time | Weak, breaks across devices and privacy resets |

The rule of thumb: **your attribution quality is capped by your identity quality.** If you can only stitch 60 percent of journeys back to a real person, then 40 percent of your conversions arrive as orphaned fragments, and no attribution model can credit a journey it can't see the start of.

This is also where server-side data collection earns its place. Client-side tracking loses 30-40 percent of touchpoints to ad blockers and browser privacy features, and those losses are not random. They skew toward specific audiences. Losing a third of your touchpoints means a third of your journeys start mid-stream, which fragments identity and inflates the count exactly where you can least afford it. Complete data is a precondition for a clean count, not a nice-to-have on top of it. (More on this in [server-side vs client-side tracking](/articles/server-side-vs-client-side-tracking).)

## A Worked Reconciliation

Here's the full sequence on the numbers from the top of this article.

**Step 1: establish the real total.** Pull the order count from the transaction system.

```sql
-- The denominator. From the system that owns the money.
SELECT COUNT(DISTINCT order_id) AS actual_orders
FROM shopify_orders
WHERE order_date >= date_trunc('month', current_date);
-- → 320
```

**Step 2: resolve identity across touchpoints.** Join all channel events to a person via a shared key, so one buyer is one journey.

```sql
-- One journey per person, not per device or per platform claim.
SELECT
  identity_key,
  array_agg(channel ORDER BY event_time) AS journey,
  MAX(converted) AS did_convert
FROM touchpoints
JOIN identity_map USING (raw_id)   -- hashed email / user_id stitch
GROUP BY identity_key;
```

**Step 3: credit the clean total.** Now, and only now, run attribution. The models distribute the 320 real orders across the resolved journeys.

The result is not four numbers that sum to 760. It's one number, split:

<div class="not-prose my-8 bg-white border border-slate-200 rounded-lg overflow-hidden">
  <div class="px-5 py-3 border-b border-slate-200 bg-slate-50">
    <p class="text-xs font-bold text-slate-500 tracking-[0.15em]">320 ORDERS, DEDUPLICATED AND IDENTITY-RESOLVED</p>
  </div>
  <div class="px-5 py-5 space-y-3">
    <div>
      <div class="flex justify-between text-sm mb-1"><span class="text-slate-700">Google Ads</span><span class="font-semibold text-slate-900">35% &middot; 112 orders</span></div>
      <div class="h-2 bg-slate-100 rounded-full overflow-hidden"><div class="h-full bg-indigo-400 rounded-full" style="width:35%"></div></div>
    </div>
    <div>
      <div class="flex justify-between text-sm mb-1"><span class="text-slate-700">Meta Ads</span><span class="font-semibold text-slate-900">28% &middot; 90 orders</span></div>
      <div class="h-2 bg-slate-100 rounded-full overflow-hidden"><div class="h-full bg-indigo-400 rounded-full" style="width:28%"></div></div>
    </div>
    <div>
      <div class="flex justify-between text-sm mb-1"><span class="text-slate-700">Email</span><span class="font-semibold text-slate-900">22% &middot; 70 orders</span></div>
      <div class="h-2 bg-slate-100 rounded-full overflow-hidden"><div class="h-full bg-indigo-400 rounded-full" style="width:22%"></div></div>
    </div>
    <div>
      <div class="flex justify-between text-sm mb-1"><span class="text-slate-700">Organic</span><span class="font-semibold text-slate-900">15% &middot; 48 orders</span></div>
      <div class="h-2 bg-slate-100 rounded-full overflow-hidden"><div class="h-full bg-indigo-400 rounded-full" style="width:15%"></div></div>
    </div>
    <div class="flex justify-between text-sm border-t border-slate-200 pt-3 mt-3"><span class="font-semibold text-slate-900">Total</span><span class="font-bold text-slate-900">100% &middot; 320 orders</span></div>
  </div>
</div>

Same raw data. The difference is that the count got fixed before the credit got argued.

## What This Changes in the Meeting

The reason this matters is not tidiness. It's that the counting problem, left unfixed, silently decides budget.

When the performance lead argues from Google's claimed 300 and the brand lead argues from Meta's claimed 250, they're both arguing from inflated, self-serving numbers, and the louder advocate usually wins. Budget follows the argument, not the evidence. The channel that over-claims most aggressively gets funded most generously, which is exactly backwards, because aggressive claiming is a property of the platform's attribution settings, not the channel's real contribution.

Fix the count and the politics deflate. There is one total. It is not the ad platform's number, so no platform's advocate owns it. The conversation moves from "my dashboard says" to "here is how the 320 splits," and that's a conversation attribution models are built to have.

## Summary

The phrase "every platform claims credit for the same conversions" describes a counting problem wearing a crediting costume.

1. **There are two jobs, not one.** Counting decides how many conversions there were. Crediting splits them across channels. Attribution models only do the second.
2. **Summed platform claims always exceed reality**, because of overlapping windows, view-through and modeled conversions, and fragmented identity.
3. **The count comes from the transaction system**, not the ad platforms. Orders are the denominator; platform claims are competing claims on that denominator.
4. **Identity resolution sets the ceiling.** You can't credit a journey you can't stitch back to a person, and complete server-side data is what keeps the stitch rate high.
5. **Only then run the model.** A clean total, split by attribution, is defensible. A model run on double-counted data is sophisticated nonsense.

Agree on the number of sales first. The argument about credit gets much shorter once everyone is dividing the same number.

## Further Reading

- [Why Your GA4, Meta and Google Numbers Don't Match](/articles/platform-reports-dont-match) — the crediting-side view of the same mechanics
- [Is Your ROAS Real?](/articles/roas-inflation-platform-over-reporting) — what over-claiming does to your return numbers
- [Server-Side vs Client-Side Tracking](/articles/server-side-vs-client-side-tracking) — why data completeness sets the count
- [What is Multi-Touch Attribution?](/articles/what-is-multi-touch-attribution) — how credit gets distributed once the count is clean

## Key takeaways

- Platforms claiming overlapping credit is a counting problem, not a model problem
- Summed platform conversions always exceed real orders, often by 40-90%
- Deduplication and identity resolution decide the total; attribution only distributes it
- Fixing the model before fixing the count is optimising the wrong layer
- One deduplicated conversion number ends most channel arguments before they start


## FAQ

**Why does every platform claim credit for the same conversion?**

Because each platform can only see its own touchpoints and is measured on the conversions it can plausibly claim. If a buyer clicked a Google ad, then a Meta ad, then converted, Google claims the sale under its 30-day click window and Meta claims it under its 7-day window. Both are following their own rules. Neither is lying. But it is one order, counted twice.

**How do I know how many conversions I actually had?**

Use the system that owns the transaction, not the systems that advertise to it. Your Shopify, Stripe, or CRM order count is the real number. Ad platforms report claimed conversions, which include view-through, modeled, and cross-platform overlap. Start from the transaction system and work backwards.

**What is the difference between deduplication and attribution?**

Deduplication decides the total number of conversions by removing double-counts, so one sale counts once. Attribution decides how to split credit for that total across channels. Deduplication produces the denominator; attribution splits the numerator. You have to fix the denominator first, or every attribution model divides up a wrong number.

**Why does model choice not fix the double-counting?**

Attribution models take a set of conversions and distribute credit across the touchpoints on each journey. They assume the conversion count is already correct. If Google and Meta both fed the same order into your data as two separate conversions, a Markov or Shapley model will faithfully distribute credit for two conversions that were really one. The model is doing its job on bad input.

**What is identity resolution and why does it matter for counting?**

Identity resolution is stitching events from the same person together across devices, sessions, and channels, usually via a shared key like a hashed email or a logged-in user ID. Without it, one buyer who researches on mobile and converts on desktop looks like two people with two separate journeys. Your count inflates and your journeys fragment. Attribution quality is capped by identity quality.

**Do I need a third-party tool to get one conversion number?**

Not always. If you can join ad-platform data and GA4 exports to your order table in BigQuery on a shared identity key, you can deduplicate yourself. The work is the identity stitching and the maintenance, not the SQL. A server-side attribution tool does the same join for you and keeps it working through platform API changes. Either way, the deduplicated order count is the deliverable, and it has to come from the transaction system, not the ad platforms.


