What Shopify's COGS report leaves out

Shopify's profit reports stop at net sales minus a static cost field. Here is what that field does to your history, and what sits below gross profit.

Shopify20 Aug 20267 min read

Ibrahim Ölmez

Founder, nouz

Shopify's profit reports answer one question: net sales minus the product cost it had on file, which it calls gross profit. Three mechanics decide whether even that number is right. The cost per item field holds a single static value captured at the moment of the sale, sales made before a cost was entered are left out of the report rather than counted, and nothing below gross profit exists in the report at all. In one example store, the costs sitting below gross profit came to €5.152.163,10 over fourteen months, which is 41,55% of net revenue.

None of that is a flaw. Shopify records what customers paid with real precision: orders, discounts, taxes and returns, to the cent, on the right day, and its help pages are candid about what the cost field can and cannot do. The argument is about scope, not competence. What follows is the mechanical version, behaviour by behaviour, and what each one does to the number you read.

Shopify's cost field has no history

Every variant has one Cost per item field. It holds one number, it carries no dates, and entering it is optional. The help page for profit reports states the consequence plainly.

The Cost per item field contains static data, which means that the data in your profit reports is only relevant to a specific point in time.

In practice the cost is captured when the sale happens. Change the field today and yesterday's report does not move, which is better behaviour than the spreadsheet everyone starts with, where editing one cell silently reprices three years of orders. The same design has two costs of its own. You cannot correct a past order, because there is no way to put a cost back into a sale that did not carry one. And you cannot hold two facts at once: what a unit cost you in March and what it costs you now. The field only knows now.

The fix is effective dating. A cost rule carries the day it takes effect, so saving a new value closes the previous one the day before and opens a new one, and every order stays priced by the rule that was true when it was placed. Backdating is still possible, but it becomes a deliberate act that reprices the days from that date forward and nothing earlier.

An example store shows what that buys you, on a cost that is not even a product cost. Its return handling charge was €1,25 per returned shipment until 1 Apr 2026 and €1,50 from that day on. A return processed on 20 Mar 2026 is still priced at €1,25 today and always will be; one processed on 20 Apr 2026 is priced at €1,50. Neither figure moves when the next price change is entered. Every cost in nouz behaves that way: product costs, the shipping rate card, pick and pack, packaging, payment fee rules and fixed costs.

Missing costs are not treated as zero, they are dropped

A variant with no cost does not report a 100% margin in Shopify's profit reports. It is left out of them. The help page for those reports says which sales are counted.

The report only takes into consideration the variants that have product cost information at the time of sale.

The finance reports go further and name the gap: net sales are split into the part where a cost was recorded at the time of the sale and the part where it was not, and only the first counts towards gross profit. That is an honest design and a better one than the alternative, because a blank treated as €0,00 turns your worst documented product into your most profitable one.

The catch is what it does to a percentage. If two thirds of your catalogue carries a cost, your gross margin is a true statement about two thirds of your sales, sitting next to a revenue chart that covers all of them. Neither number is wrong and the comparison between them is meaningless. The gap is only visible if you go looking for it, and blanks do become zeros the moment the data leaves Shopify for a spreadsheet or a tool that multiplies whatever it finds in the field.

nouz takes the third option. The sale still counts, the missing cost is reported as a data health warning on the Products page with the variants named, and an unset cost is never quietly treated as €0,00. A gap you can see is a task. A gap you cannot see is a wrong number.

Refunded units and which day they land on

Shopify dates the revenue side of a refund the same way nouz does, and that is worth saying on a page like this one. From the sales reports documentation:

Returns display as a negative number on the date the return was processed.

The cost side is the harder half, and two questions decide it: which day the credit for the returned unit lands on, and at what cost that credit is valued. Any report that nets refunded units against sold units inside whichever date range you picked answers both questions with the range. Ask it about June and you see a sale with no credit. Ask it about August and you may see a credit with no sale. Neither view is wrong so much as partial, and a margin percentage read off either one is doing arithmetic across two different populations.

nouz answers both questions explicitly. The credit lands on the refund date, beside the refunded amount, the refunded tax and the cost of processing the return. It is valued at the cost rule effective on the original order date, so the credit matches the original debit to the cent, and a supplier price change between the sale and the return can never manufacture a gain or a loss that nobody made. That rule is subtle enough to deserve its own post.

Nothing below gross profit exists

The profit reports are gross profit by product, gross profit by product variant, gross profit by POS location, average profit margin by market, and profit margin by order. Every one of them is net sales minus the recorded product cost. There is no line below that and nowhere to put one. The revenue half of this argument is made in what Shopify Analytics does not tell you; this is the cost half.

So none of the following reaches the report: your shipping rate card by zone and weight, pick and pack, packaging, packaging EPR fees, the cost of processing a return, the payment provider's percentage and fixed fee, what you spent on Meta, Google and TikTok yesterday, and rent, salaries, software and agency retainers. Some of that data does exist inside Shopify. If you use Shopify Payments, the fees are in your payouts and in the payments activity report, in a different place and in different units, and they never touch gross profit. A PayPal or Klarna fee is not in Shopify at all.

Cost groupOver the windowShare of net revenue
Logistics€1.046.422,498,44%
Transaction costs€426.721,513,44%
Marketing€3.144.072,3425,36%
Overhead€534.946,764,31%
Total below gross profit€5.152.163,1041,55%
In one example store, over the fourteen months from 1 Jul 2025 to 20 Aug 2026, the four cost groups that sit below gross profit came to this.

That store's CM1, which is net revenue minus product cost, was €7.534.047,38 or 60,76% of net revenue. Its EBITDA was €2.381.884,28 or 19,21%. The distance between the two is the table above. A report that stops at gross profit hands you the first figure, and gross profit is CM1 at best, and only if the cost field was complete on the day of every sale. It is not exactly CM1 either: Shopify's net sales leaves shipping revenue out, so the two are the same shape rather than the same number.

Shopify's own help page for profit reports points merchants who need more than a static cost towards an accounting system or a reporting app. That is a fair description of where the boundary sits, written by the people who drew it.

What a complete answer needs

Four cost engines, and all four are bookkeeping rather than cleverness. Each is a short piece of setup you do once and then amend as prices move, which is the only ongoing work involved once the store is connected.

  • Product cost per variant, dated, so that March is priced at March, with every missing cost named instead of assumed.
  • Logistics per parcel: a rate card by zone and weight, pick and pack, packaging, packaging EPR where it applies, and return processing on the day the refund is issued.
  • Payment fees per gateway: a percentage plus a fixed fee per transaction, applied to what was actually charged, including an order split across two payment methods, and any chargeback fee.
  • Ad spend from every platform on the day it was spent, and fixed costs spread across the days they cover rather than landing whole on the day the invoice arrived.

Put those four under the revenue Shopify already records accurately and the statement keeps going: net revenue, then CM1 after the goods, CM2 after fulfilment and fees, CM3 after advertising, and EBITDA after the fixed costs. A statement that stops at cost of goods sold answers a smaller question, and it answers it well. It is just not the question you were asking.

Written by

Ibrahim ÖlmezFounder, nouz

Builds the P&L engine behind nouz. Writes about the costs that decide whether a Shopify store is actually profitable.