Why the ad platform and your checkout never agree
Every launch meeting has this argument. The numbers disagree because they measure different things — and there is a way to stop debating and start measuring the gap.

Ads Manager says 180 sales. The checkout says 143. Media defends the first number, finance defends the second, and the meeting becomes a debate about who to believe. That argument is old and has a boring answer: both are right, because they are measuring different things.
The four reasons for the gap
1. Attribution window
Meta credits the sale to the day of the click, not the day of the purchase. Someone who clicked on Monday and bought on Friday shows up on Monday in Ads Manager and on Friday in your checkout statement. During a launch with a seven-day cart, that alone decouples the entire series.
2. View-through attribution
By default Meta also attributes sales to people who merely saw the ad without clicking. That is a defensible modeling choice, but it has no counterpart in the checkout — which only knows about people who arrived.
3. Events lost in the browser
In the other direction, Meta loses sales: blockers, closed tabs and tracking restrictions kill part of the fires. Here Meta’s number comes in lower than reality.
4. Payment status
If the event fires when an invoice or a pending payment is generated, unpaid orders count as sales. The statement only counts what was approved. In products with many delayed payment methods, the difference is enormous.
Notice the causes push in opposite directions. "The ad platform inflates" is therefore an incomplete explanation: in cold traffic campaigns with privacy-conscious audiences, it frequently undercounts.
What to do about it
- 01Pick one source of truth for money. It is the payment gateway, always. The number that becomes cash is the checkout’s, and that is the one that goes in the results report.
- 02Use the ad platform as an optimization signal, not as accounting. Its job is to teach the algorithm, and for that it needs clean data — not data identical to yours.
- 03Feed the ad platform the real sale. Sending approved purchases through the Conversions API, with value and identity, improves the signal and shrinks the gap caused by lost events.
- 04Measure the gap instead of arguing about it. With ad cost and checkout sales in the same base, the divergence becomes a column in the report, monitored like any other metric.
The comparison that actually matters
Once both sources sit in one place, you can ask the only question that decides investment: of the sales the checkout recorded, how many can be tied to an ad — and to which one? That is a question about your own data, and it does not depend on believing anyone’s report.
SELECT
m.campaign_name,
SUM(m.spend) AS spend,
COUNT(DISTINCT s.transaction_id) AS checkout_sales,
SUM(s.price_value) AS real_revenue,
SUM(s.price_value) / SUM(m.spend) AS roas
FROM meta_ads m
LEFT JOIN checkout_sales s
ON s.meta_campaign_id = m.campaign_id
WHERE s.status IN ('APPROVED', 'COMPLETE')
GROUP BY 1
ORDER BY real_revenue DESCA share of sales will tie to no ad at all, and it should stay visible in the report. Hiding the unattributed portion is the fastest way to produce a return figure that is beautiful and false.