How to Fix Shopify ↔ Meta Revenue Discrepancy (With Real Numbers)
Step-by-step guide to reconcile Shopify and Meta revenue—diagnostics, Pixel+CAPI dedup fixes, refunds handling, and worked-number examples.
If Shopify and Meta Ads report different revenue for the same period, you’re not alone. The two systems count conversions under different rules (attribution windows, click vs view, modeled conversions), and they receive signals through two pipes (Pixel and Conversions API) that can double‑count if misconfigured. The good news: you can reconcile the gap with a simple, repeatable workflow and a little spreadsheet math.
Before you start, wait 48–72 hours after the period ends to let Meta modeling settle and Shopify analytics finalize. Then budget 30–60 minutes for a weekly run‑through.
Key takeaways
Define a single comparison baseline first: Shopify Net or Total Sales, and Meta 7‑day click vs 1‑day view, using Ads Manager’s attribution comparison.
Verify Pixel + CAPI deduplication with a shared event_id and a 48‑hour window; otherwise Meta can double‑count the same Purchase.
Handle refunds as an explicit line item. Standard web CAPI doesn’t decrease Ads Manager Purchase value; you subtract refunds in your workbook.
Align time zones and currency before any math; a PST vs UTC mismatch can skew boundary days.
Adopt a weekly reconciliation loop with thresholds; investigate only when the unexplained delta breaches your tolerance for two consecutive weeks.
Standardize what you’re comparing
Start by agreeing on definitions:
On Shopify, many finance teams use Net sales (gross minus discounts and returns, excluding shipping and taxes). Shopify’s “Sales by billing period” defines Gross, Net, and Total sales precisely; use this to pick your baseline and document it for stakeholders. See Shopify’s definitions in Sales by billing period for Gross/Net/Total sales: Shopify sales report definitions.
On Meta, Purchases and Purchase value depend on the attribution window. Most teams compare 7‑day click against a click‑sourced order set from UTMs. Ads Manager lets you split metrics by attribution using “Compare attribution settings” so you can see 7‑day click alongside 1‑day view. Meta’s Ads Insights API supports these windows (for example, 7‑day click and 1‑day view), which is why the UI can render them in parallel: Meta Insights API attribution windows.
Put simply: pick Shopify Net or Total as your baseline and choose whether your marketing view is click‑only or click+view. Document those rules in your workbook header so no one moves the goalposts mid‑quarter.
Diagnose the Shopify Meta revenue discrepancy: Quick workflow
Run this workflow once a week. It’s fast, predictable, and makes the variance easy to explain.
Confirm time zone and currency settings in Shopify Admin, then standardize your extracts to one time zone and the base currency. Shopify’s help center outlines where time zone and currency are controlled in the Markets settings area: Shopify time zone and currency.
In Meta Ads Manager, use Columns > Customize > Compare attribution settings to add Purchases/Purchase value under 7‑day click and 1‑day view. The underlying capability comes from the Insights API: Attribution windows in Meta’s Insights API.
Export Shopify Orders as CSV for the period. If you need to audit refunds precisely, include refund fields; Shopify documents the Orders export and the CSV columns: Export Orders and CSV columns.
Fill the workbook with these columns (see table below). Use your chosen Shopify baseline (Net or Total) and split Meta into click and view if you plan to track view‑through share.
Do the reconciliation math. If the unexplained delta (after accounting for refunds and dedup fixes) is above your threshold for two consecutive weeks, escalate.
Two blank lines before and after tables
Date | Shopify Net Sales | Shopify Total Sales | Refunds | Meta Purchase (7d Click) | Meta Purchase (1d View) | Explained Delta |
|---|---|---|---|---|---|---|
2026‑04‑14 | 12,500 | 13,300 | 600 | 9,000 | 2,200 | =B2−D2−E2−C2 |
2026‑04‑15 | 14,200 | 15,050 | 500 | 10,100 | 2,700 | =B3−D3−E3−C3 |
Two blank lines before and after tables
Example Excel formulas you’ll actually use:
If your finance view is click‑only and you use Net as baseline: Unexplained delta = Shopify Net − Meta 7d Click − Refunds
If you track view‑through as a separate line: Unexplained delta = Shopify Net − Meta 7d Click − Meta 1d View − Refunds
Guardrails:
Wait 48–72 hours from period close before running this.
Investigate if the unexplained delta exceeds ~15% for two consecutive weeks; if it’s mostly view‑through share, your click‑only rule may be the driver rather than a tracking bug.
Verify Pixel and CAPI deduplication
Without proper deduplication, Meta can count the same Purchase twice—once from the browser Pixel and once from your server. Meta deduplicates when both events share the same event_name (Purchase) and the same event_id. See Meta’s server event parameters: event_id for deduplication. The maximum deduplication window is 48 hours, which gives you a clear validation SLA: 48‑hour dedup window. Use Events Manager Diagnostics/Test Events to verify event parity and Event Match Quality: Verify setup and Diagnostics.
One working pattern is to generate a UUID in the browser, pass it to the Pixel and to your server, and reuse it when sending the CAPI event. Think of the event_id as the order’s boarding pass—if both the gate agent and the app scan the same pass, the airline knows it’s the same person.
// Browser: Meta Pixel with a shared event_id
const eventId = crypto.randomUUID();
fbq('track', 'Purchase', {value: 129.99, currency: 'USD'}, {eventID: eventId});
// Send the same eventId to your server with order details
fetch('/capi/purchase', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({eventId, value: 129.99, currency: 'USD', email: user.email})
});
// Server: Conversions API call (Node-style pseudo)
const payload = {
event_name: 'Purchase',
event_time: Math.floor(Date.now()/1000),
event_id: eventId, // must match the Pixel eventID
action_source: 'website',
user_data: {em: hashSHA256(user.email)},
custom_data: {value: 129.99, currency: 'USD'}
};
// POST payload to: https://graph.facebook.com/v17.0/<PIXEL_ID>/events?access_token=<TOKEN>
Validation checklist in Events Manager:
Recent events show Purchase once per order, marked as deduplicated.
Value and currency match between Pixel and CAPI.
Event Match Quality is healthy; if not, improve hashed identifiers (email, phone) where consent allows.
Handle refunds and post‑purchase adjustments
Here’s the deal: standard web Conversions API does not provide a “refund” event that subtracts from Ads Manager Purchase value. Refund state sync exists for Meta Shops via the commerce refunds APIs (useful if you operate a Meta Shop rather than a standalone Shopify site): see Meta’s commerce cancellation and refund API overview: Meta commerce cancellations and refunds.
For a typical Shopify website running Pixel+CAPI, you account for refunds in reconciliation math:
If your baseline is Net sales, refunds are already deducted by Shopify; make that explicit in your sheet notes.
If your baseline is Total sales, subtract refunds as a separate line.
From the Shopify side, export Orders (or filter for refunded orders) and read the refund columns defined in the Orders CSV documentation so you don’t miss partial or shipping‑only refunds: Shopify Orders export and CSV columns.
Align time zones and currency before you compare
Time zone and currency are silent drift factors. If your store runs in PST and your Meta account rolls up in UTC, the same calendar day won’t line up; one will include late‑night purchases that the other pushes to the next day. Confirm your store’s time zone and base currency in Shopify Admin and standardize all extracts to a single time zone/base currency for reconciliation. Shopify provides guidance on time zone and currency settings within its Markets documentation: Shopify time zone and currency.
Operational notes:
Changing the store time zone affects future data but doesn’t retroactively shift past orders.
If you sell in multiple currencies, convert to the base currency before comparisons.
Give reports time to settle. Shopify’s analytics overview explains how reports populate and update; plan your weekly run accordingly: Shopify analytics overview.
Worked examples with real numbers
Let’s dig in with concrete math you can copy into your sheet.
Example A — Attribution windows
Period: Last 7 days
Shopify Total Sales (after discounts; including tax+shipping): $100,000; refunds posted: $5,000
Meta reports:
7‑day click + 1‑day view Purchase value = $60,000
7‑day click only = $45,000
1‑day view only = $12,000 (implies $3,000 overlap from engaged views)
Reconciliation paths:
Click‑only finance view: Compare Shopify orders sourced from Meta UTMs to Meta 7‑day click value.
Example math (click‑only, using Net or subtracting refunds): If your baseline is close to Net = $100,000 − $5,000 = $95,000; Meta 7‑day click = $45,000. Residual = $95,000 − $45,000 = $50,000. That remainder reflects a mix of organic/other channels, multi‑touch paths where Meta wasn’t last click, and privacy‑driven losses.
Example B — Refunds not reflected in Meta
Shopify refunds in the period: $8,000
Meta Purchase value shows $50,000 (Meta doesn’t decrement via web CAPI)
Fix: Subtract refunds in your sheet.
If baseline is Net, confirm refunds are already deducted and annotate the note column: “Net includes $8,000 refunds.”
If baseline is Total, compute Marketing‑adjusted revenue = Total − Refunds. Example: Total = $52,000; Marketing‑adjusted = $52,000 − $8,000 = $44,000 vs Meta click‑only.
Example C — Deduplication error inflating Meta revenue
Pixel Purchase value: $20,000; CAPI Purchase value: $20,000
Dedup missing ⇒ Ads Manager shows roughly $40,000
Fix: Ensure Pixel and CAPI share the same event_id for Purchase within 48 hours and validate in Events Manager Diagnostics. After fix, Meta reports ~$20,000 (minor differences may remain due to modeling/time).
Example D — Time zone alignment
Shopify store time zone: PST; Meta account: UTC
On a boundary day, Meta shows $7,500 and Shopify shows $5,000
After converting both extracts to UTC for that day, totals align within ~3%. The prior gap was a reporting clock issue, not a tracking bug.
When the gap persists: thresholds and next checks
Even after you fix windows, dedup, refunds, and time zones, some variance remains. What’s acceptable? As a practical heuristic, if your unexplained delta is under ~10% over a two‑week window, you’re in healthy territory for direct‑response purchase campaigns. If it’s above ~15% for two consecutive weeks:
Re‑check attribution settings in Ads Manager to confirm no recent changes to windows.
Review Events Manager Diagnostics for parameter mismatches (value, currency) and low Event Match Quality.
Confirm no sudden channel mix shifts (e.g., upper‑funnel bursts raising view‑through share). Meta’s modeling can increase view‑through contributions after privacy shifts; always compare windows side‑by‑side using the API‑supported attribution view: Meta Insights API attribution windows.
Finally, document your chosen baseline (Shopify Net vs Total) and window rules in the sheet. If leadership asks, “Why doesn’t Meta equal Shopify?”, you can point to the specific factors and numbers that explain the gap.
Optional tools to speed up your loop
If you prefer a standardized handoff between Shopify orders, server‑side events, and windowed reporting, a tracking platform can help centralize setup and reduce manual steps. For example, Attribuly can be used to connect Shopify Web Pixels and send server‑side Purchase events to Meta while letting teams standardize analysis windows in one place: Attribuly Meta Ads integration. Keep the workflow neutral: validate dedup in Events Manager, and continue to reconcile refunds in your sheet unless your commerce stack supports refund‑state sync directly with Meta Shops.
What “good” looks like after two weeks: your sheet shows a small and stable unexplained delta, view‑through share that matches your funnel mix, and clean deduplication. Save the workbook, freeze your comparison rules, and run the loop weekly. That’s how you turn a noisy Shopify ↔ Meta discrepancy into a reliable operating ritual.