The symptom: three numbers that don't tie out
It's the most repeated conversation in Monday meetings. Ads Manager reports a 9x ROAS and everyone wants to scale. The finance director opens Shopify, sees the month's sales, and asks why they don't show up anywhere. Someone suggests "let's just trust Meta, the pixel is right there," and budget for next month gets decided on that figure.
The problem isn't that one platform is lying. The problem is that Meta and Shopify are answering different questions, and almost nobody makes it explicit which of the two should drive the budget decision.
Where the gap comes from, in order of size
When we audit an account, the gap between what the platform reports and what hit the bank is almost always explained by these five causes — in this order:
1. The attribution window
By default, Meta credits itself with any purchase that happens within 7 days after a click or 1 day after a view. If the customer saw your ad on Monday, searched your brand on Google on Thursday and bought there, Meta counts that sale as its own. So does Google. The same sale shows up twice if you add up both platforms' reports — and adding them up is exactly what most people do.
2. Modeled conversions
Since iOS 14.5 and the end of third-party cookies, part of what you see in Ads Manager isn't observed: it's estimated statistically. It's a reasonable estimate in aggregate, but it isn't an order you can trace back to an order number. It can't be reconciled against the bank because, literally, it doesn't exist as an individual transaction.
3. Refunds and cancelled orders
Meta records the conversion at the moment of purchase and leaves it there. If the customer returns the product three weeks later, that sale stays alive in your ads report forever. In categories with high returns this inflates ROAS permanently and silently.
4. Channels that aren't attributable to digital
This is the one that muddies the numbers most and the one almost nobody separates. If you also sell on marketplaces or through a B2B channel manager, those sales land in Shopify and fatten your total — but your ads didn't generate them. Rolling them into ROAS makes you believe the ads perform better than they do. In one brand we run, excluding the B2B channel changed the read of the month completely.
5. Payment status
The most technical one, and the one that hides the most money. If your report only filters orders with a paid status, you're dropping pending, partially paid, partially refunded and cancelled orders. We've found accounts where that one filter disappeared between 5% and 8% of point-of-sale revenue — a gap nobody noticed because the report "looked fine."
The rule that sorts it all out: one source of truth
Our stance after running this in production is simple: the platform is for optimizing, not for reporting.
Meta is excellent for deciding which creative to pause, which audience to scale and how to split within the account. Its attribution is useful for that, biases and all. But the figure used to decide how much to invest next month has to come from Shopify, reconciled against the bank. One source, defined in advance.
That's where blended ROAS comes from: the period's real sales divided by all the spend in the period. It doesn't depend on anyone's attribution, it can't be inflated by double-counting, and it can be tied out against an official report.
The method, step by step
Here's how we set it up, and in this order:
- Pull every payment status. No filtering by paid in the query. You pull every order and the refunds already netted out, so the total reflects what's current, not what was originally invoiced.
- Tag each order's channel. Online store, point of sale, draft order, marketplace, B2B. Without this tag it's impossible to decide what goes into ROAS and what doesn't.
- Define the attribution rule in writing. Which channels count, which are excluded and why. Documented once, not changed between reports — and if it changes, the full history gets recomputed.
- Impute refunds to the day they were processed, not the day of the original order. That's how Shopify computes its returns, and if you do it differently you'll never tie out in the daily view.
- Tie out against the official Shopify report for the same range and the same channels, before you show the dashboard to anyone.
What counts as an acceptable margin
This is the standard we hold internally: a dashboard should tie out within 0.1% against the official Shopify report for the same range and the same channels. In the accounts we run we reach exact-to-the-peso matches in most locations, with residuals under 0.02% explained by documented edge cases — a refund processed by terminal days later, typically.
If your difference is 3%, 5% or "somewhere around there," you don't have a rounding problem. You have a filter set wrong, a channel not separated, or refunds not netted out. And you're deciding budget on that figure.
What changes when you close the gap
The first thing that changes is the conversation. You stop arguing about which number is the right one and start arguing about what to do. The second is that hidden decisions surface: campaigns that looked profitable on platform attribution and aren't on a blended basis, and campaigns that looked mediocre and were actually assisting in-store sales.
At Brüm, operating on this reconciled read is what sustains a blended ROAS of 11.5x with sales growing 50% year over year. Not because the number looks nice, but because every decision to scale was made on a figure that ties out with the bank.
Frequently asked questions
Why does Meta report more sales than Shopify?
Because it claims any sale inside its window (7-day click / 1-day view) even if another channel closed it, and because it models conversions it doesn't observe directly. Shopify only records the order that came in. Meta answers what did I influence; Shopify answers what did I sell.
Should I include in-store sales in ROAS?
For high-ticket brands with stores, a good share of physical sales arrive assisted by an ad: the customer sees the ad, messages on WhatsApp and closes in store. Excluding it understates real performance. What's critical isn't what you decide, but that the rule is set once and doesn't move between reports.
And if I sell on marketplaces?
Separate it from digital ROAS. It's real revenue and belongs in your income report, but your ads didn't generate it. Mixing it in will make you scale campaigns that aren't performing.
Do I need a BI tool for this?
No. It's solved with read-only API access and three scripts. We wrote the full architecture in this post on the dashboard that updates itself three times a day, and it's what we build under the Data & Dashboards capability.
Two projects per quarter
Start with the number you don't have.
Three weeks, read-only access, no cost, and a written scope you keep, whether you continue or not.
NEXT ON THE BLOG → OWN CRM VS. RENTING SAAS: WHEN IT PAYS TO BUILD YOUR OWN