Why do my inventory counts and COGS go haywire every time someone returns or exchanges an order?
Refunds that skip restocking, exchanges that look like phantom new orders, and a stale cost field can all quietly wreck your numbers. Here's what Shopify actually does at each step and how to keep it accurate.
What's going on
Every return or exchange forces a store owner to answer three questions at once: did the stock come back, did the money come back, and did the true cost of that sale change? Shopify's admin lets you handle all three loosely if you're not careful — refunding an order without touching inventory, restocking items nobody has actually inspected yet, or processing an exchange and then wondering why it shows up as a brand-new sale in your revenue reports. None of this is broken; it's just easy to get wrong if you don't know how the pieces connect.
The symptom merchants usually notice first is inventory drift: on-hand counts that stop matching what's physically on the shelf because some returns got restocked and others were refunded with no inventory action at all. The second thing they notice, usually later and more painfully, is that margin and COGS reports don't reconcile — often because the Cost per item field on a product was never updated after a supplier price change, so every return and refund calculation downstream is quietly wrong.
Why it happens
Shopify treats the refund, the restock, and any exchange order as separate actions you have to trigger deliberately. Restocking isn't automatic just because a refund happened — you have to choose to restock and pick a location during the return, and if you skip that step (or refund at the order level instead of by line item), your inventory and returns reporting won't reflect what actually happened.
Exchanges add a second layer because Shopify doesn't modify the original order to swap an item in place — it returns the original product and creates a separate, discounted order for the replacement. That's expected behavior, but anyone reconciling by order count or revenue will see two transactions where they expected one, and can easily misread it as a duplicate or a new customer order.
Underneath both of these, COGS and margin reporting depend on the Cost per item value stored on each product variant. When that field falls out of date after a supplier or landed-cost change, every downstream return, refund, and profitability figure inherits the stale number, no matter how cleanly the return itself was processed.
5 ways to fix it
Restock deliberately through the Return flow, not by default
In the Shopify admin, open the order and start a return rather than issuing a plain refund. During that flow you choose whether to restock the item and at which location, and that choice is what actually puts the inventory back and creates a traceable adjustment tied to the order. Don't restock everything automatically: for anything that needs inspection first (apparel, electronics, anything resellable only if undamaged), leave it unrestocked until someone has physically checked it, then adjust inventory manually once it clears. This one habit fixes most inventory drift and costs nothing to adopt.
Process returns as line items, not as a lump-sum order refund
If your team's habit is to refund the full order amount without going through the return flow, that refund won't be tied to specific SKUs or reflected in your returns reporting the same way. Refunding through the Return/exchange flow, item by item, keeps a per-SKU record of what was actually sent back, which is what lets your reports (and your bookkeeper) later distinguish "refunded, item never returned" from "refunded, item restocked and resold."
Know that an exchange is really two transactions, not one swap
When you add a replacement item to a return, Shopify doesn't edit the original order in place — it processes the return of the original item and creates a new order for the replacement, discounted so the customer's balance nets out correctly. That means your order count, revenue, and COGS reports will show an outbound return plus a separate new sale rather than one clean exchange. Flag this pattern for whoever reconciles your books so an exchange doesn't get misread as a brand-new sale or double-counted.
Check your Cost per item field before you chase reporting bugs
Shopify's margin and cost-of-goods figures are only as accurate as the Cost per item value stored on each product variant. If that number hasn't been updated since your last supplier price change, duty adjustment, or shipping cost increase, every return, refund, and margin report built on top of it will be off — no matter how correctly you process the return itself. Review and update cost fields on a regular schedule, not just when something looks wrong.
Reach for a dedicated returns app only once native reporting stops being enough
Shopify's built-in return tools handle status, restocking, and basic reporting, but they don't total up the real cost of a return (labor, return shipping, write-offs) or roll return reasons up into a profitability view. If you genuinely need that, returns-management apps in the Shopify App Store can add richer reporting and automated restocking rules on top of the native flow. Before adding one, check whether your accounting software or 3PL already covers it — an extra app mainly pays for itself once manual reconciliation is the actual bottleneck, not before.
Bottom line
None of this requires new software to get right. Used consistently, Shopify's native return and exchange flow, line-item refunds, and an up-to-date Cost per item field already give you an accurate inventory and COGS picture. A returns-management app earns its place once you need automated restocking rules or return-cost reporting the native admin doesn't provide — evaluate any app on its reporting depth and integrations, not just price.
Browse the rest of the problem library, run a free storefront scan to catch issues like this automatically, or email us and we'll work out a custom solution for it.