Making revenue reports match Shopify to the day
Rebuilding a Shopify data platform’s sales reporting on Shopify’s own definitions, then repairing the data underneath it in production.
283/288
days in 2026 matching Shopify in every column
5,005
skipped refunds recovered from Shopify
3,334
double-imported orders removed, after a backup
~64K
orders backfilled with their edit dates
01 —Context
Risify is a Shopify data platform. It syncs a merchant’s orders, products and ad spend and turns them into profit reporting: daily totals, monthly profit, an annual report. The people who read those reports also have Shopify Analytics open in the next tab. When the two disagree, they believe Shopify, and then they stop believing the rest of our dashboards too.
02 —Problem
Our figures drifted from Shopify’s in ways that were hard to explain one day at a time, because each report had grown its own idea of what “sales” meant. Revenue only counted paid orders, so partially refunded orders and orders still awaiting payment quietly fell out, nearly 5,400 of them, and every new payment state Shopify introduced broke the rule again. Refunds were credited to the month the order was placed instead of the day the money went back, so closed days were rewritten months later.
Underneath the definitions, the data itself had holes: refunds the bulk import had never collected, missing shipping refunds and shipping lines, and order edits with no date.
03 —What I did
I stopped debating definitions and adopted Shopify’s. The trade-off was that some historical figures would move, and people would need to be told why.
- Rebuilt the Daily Total Orders report on the definitions behind Shopify’s own sales report: every order that is not cancelled counts, and refunds, exchanges, return fees and order edits are dated on the day they happen. Then moved Monthly Profit, Annual Report and Daily Profit onto the same calculation, so four reports show one number for the same day.
- Made drift visible instead of guessed at. A reconciliation view compares our figures with Shopify’s reported totals month by month: a disagreement in order count is an error, a money-only difference is a variance to watch. A nightly check does the same against Shopify’s daily totals. This is what found six days in March where 274 orders had never reached us.
- Repaired history in production as commands with dry runs and acceptance criteria, checked after each run: 5,005 refunds on 4,398 orders that the bulk import had skipped, missing shipping refunds, 79 removed shipping lines, and edit dates for about 64,000 orders.
- Found the last gap: an import from mid-2025 had written 3,334 orders twice, with their shipping lines attached to the wrong copy. I took a backup first, then removed the duplicates in production.
- Kept the metric glossary in step with the code (58 definitions at the end) and walked the owner of the numbers through every change that moved a figure.
04 —Result
Daily Total Orders now matches Shopify in every column on 283 of 288 days in 2026, and monthly Total Sales across the other reports differs from Shopify by about 0.003%. After the duplicate cleanup, Total Sales disagreed with Shopify on a single day and no month was flagged in Diagnostics. The business owner of the reports checked the new figures against Shopify and signed them off.
05 —What I’d do differently
I would build the reconciliation first. For months the reports were wrong in ways nobody could see, and the check that compares us with Shopify should have existed before the first dashboard did.
I would also treat “cleaned up” and “cannot happen again” as two separate pieces of work from day one. I know what the duplicate import did, but not yet why, so until that is found it can recur.