Shopify sellers export product and inventory CSVs constantly — a price update before a seasonal sale, a fresh stock count after a shipment lands, a supplier feed merged into the catalog ahead of a bulk re-import. Each export looks like a flat grid of Handles, SKUs, prices, and quantities, and it's tempting to edit the file and import it straight back in. The trouble starts when two exports taken at different times need to be compared first: did the price update apply to all 40 variants or only 38? Did the stock count for a fast-moving SKU change between the export and the import? Shopify's own import screen will eventually flag a stale inventory count, but it has nothing to say about price changes, new variants, or rows that quietly disappeared. Diffing the two files yourself, before clicking import, catches all of it — not just the one thing Shopify happens to check.
Match two Shopify exports by Handle or Variant SKU and csvdiff.app shows exactly which rows were added, removed, or modified — price changes, stock changes, new variants, discontinued SKUs — color-coded and reviewable in seconds. Resolve any conflicting values per cell, then export a clean CSV ready to re-import. Because the diff runs entirely in your browser, a catalog file with cost prices or supplier terms attached never has to touch a third-party server to get checked.
Where Shopify's Own Import Checks Fall Short
Shopify does build in one safety check, and it's worth understanding exactly what it covers. The inventory CSV export includes an On hand (current) column — a snapshot of stock levels at export time — alongside an On hand (new) column you fill in with updated counts. On import, Shopify compares On hand (current) against your store's actual live inventory. If the two don't match, because new sales happened after you exported, the affected rows are rejected and you get an email listing the failures. That's a genuinely useful guardrail, but it's also the only one. It only fires on the inventory CSV, only checks stock counts, and only catches staleness, not correctness.
- –A bulk price edit applied via spreadsheet formula that accidentally shifted into an adjacent column
- –A variant accidentally deleted from your working copy of the file — Shopify reads a missing row as "remove this variant," not as an error
- –A SKU with a stray trailing space or changed casing, which breaks the match to your existing catalog without any warning
- –Two teammates editing separate copies of the same export and merging them back together by hand
- –A supplier feed merged into your catalog that quietly overwrites your own price or description edits
Choosing Handle, SKU, or Location as the Match Key
csvdiff.app matches rows between two files by a key column you pick, and which column makes sense depends on which Shopify export you're working with. The product CSV uses Handle as the unique identifier for a product — every variant of that product shares the same Handle, with Option1/Option2/Option3 Value columns and Variant SKU distinguishing the rows underneath it. Key on Handle if you're tracking product-level edits like title, description, or tags; key on Variant SKU if you need every variant tracked independently, which is almost always the right call, since two exports can reorder rows or gain and lose a variant without the product itself changing.
The inventory CSV is shaped differently: every row is already SKU plus Location, so SKU alone isn't unique once you stock more than one warehouse or retail location. Export and diff one location at a time, or filter both files down to a single Location before comparing — otherwise the diff will pair up rows that happen to share a SKU but represent stock in different places entirely.
| Variant SKU | Title | Variant Price |
|---|---|---|
| TSHIRT-BLK-M | Classic Tee — Black / M | 18.00 |
| TSHIRT-BLK-L | Classic Tee — Black / L | 18.00 |
| HOODIE-GRY-M | Pullover Hoodie — Grey / M | 42.00 |
| Variant SKU | Title | Variant Price |
|---|---|---|
| HOODIE-GRY-M | Pullover Hoodie — Grey / M | 42.00 |
| TSHIRT-BLK-M | Classic Tee — Black / M | 20.00 |
| TSHIRT-BLK-L | Classic Tee — Black / L | 18.00 |
Spotting What Actually Changed
Once the key column is set, the diff itself takes seconds to read. Modified rows show the old value struck through next to the new one — a price that moved from $18.00 to $20.00, a stock count that dropped from 64 to 12 — so you're not stuck eyeballing two spreadsheets side by side hunting for the one cell that's different. Added rows are new variants or new products since the last export; removed rows are SKUs that existed before and don't anymore, which on a product CSV usually means a variant got deleted, intentionally or not.
| Status | Handle | Variant SKU | Variant Price | Variant Inventory Qty |
|---|---|---|---|---|
| Modified | classic-tee | TSHIRT-BLK-M | 18.00→20.00 | 64 |
| Modified | pullover-hoodie | HOODIE-GRY-M | 42.00 | 47→12 |
| Added | pullover-hoodie | HOODIE-GRY-XL | 42.00 | 30 |
| Removed | classic-tee | TSHIRT-BLK-XS | 18.00 | 0 |
It's Not Just Shopify
The same problem shows up on every platform that manages a catalog through CSV, because the file shape is almost always the same: one row per SKU (or per SKU and location), a price column, and a stock or quantity column. WooCommerce's product export uses SKU alongside Regular Price, Sale Price, and Stock. BigCommerce's export uses SKU with Current Stock Level and a price column. Amazon Seller Central's inventory and pricing flat files key on Seller SKU with Price and Quantity columns of their own. None of these platforms diff your before-and-after for you — the match-by-key approach that works for a Shopify export works identically on any of them.
- –SKU case sensitivity — "Tshirt-Blk-M" and "TSHIRT-BLK-M" won't match as the same key on most platforms, including csvdiff.app, so a casing change anywhere in the pipeline silently splits one product into two rows
- –Currency symbols and thousands separators — a price exported as "$1,200.00" from one system and "1200.00" from another compares as different text even when the value is the same; normalize formatting before diffing two exports from different sources
- –Leading zeros in barcodes or UPCs — spreadsheet software loves to read a UPC as a number and drop the leading zero; csvdiff.app reads every column as text, so this only bites you if the file was already mangled before it got there
Resolving Conflicts and Exporting a Clean Re-Import File
Some changes you want to keep and others you don't — a supplier feed might bring in a corrected price but also overwrite a description you edited by hand. Per-cell resolution handles exactly that: every changed cell shows both values with Pick A / Pick B controls, so you keep the price from one file and the description from the other on the same row, then export a single merged CSV that's ready to hand back to Shopify's importer.
| ID | Title | Variant Price | Body (HTML) |
|---|---|---|---|
| TSHIRT-BLK-M | Classic Tee — Black | A18.00B20.00 | A<p>100% combed cotton, relaxed fit.</p>B<p>100% combed cotton.</p> |
Frequently Asked Questions
Can I diff a Shopify product CSV against an inventory CSV?
Not usefully — they're different exports with different column shapes. The product CSV carries Handle, Variant SKU, and price-related fields; the inventory CSV carries Handle, SKU, Location, and On hand counts. Compare product-to-product and inventory-to-inventory, matched against the same export type from two points in time.
What if my store has multiple locations?
Filter or export the inventory CSV one location at a time before diffing. Since each row in a multi-location export is SKU plus Location, comparing the whole file at once with SKU as the key will pair up rows from different warehouses that happen to share a SKU, which produces a meaningless diff.
Does this replace Shopify's own import validation?
No, and you'll still want both. Shopify's stale-inventory check protects against one specific failure mode at import time. Diffing your two exports beforehand catches everything else: price changes, new or removed variants, and edits that have nothing to do with stock counts at all.
Will this work for WooCommerce, BigCommerce, or Amazon exports?
Yes — pick whichever column is the unique product or variant identifier in that export (SKU on all three) as the match key, and the same row-level diff applies. The column names differ by platform; the comparison logic doesn't.
How large a catalog can csvdiff.app handle?
Comfortably into the tens of thousands of rows for most stores, since the comparison runs in the browser tab's own memory. A catalog with hundreds of thousands of SKUs and many columns will be slower to load and diff — for files at that scale, filtering to the columns and rows you actually need to check first keeps things responsive.
A price update or restock that goes out wrong on Shopify is not a typo you catch on a spot check — it stays live on the storefront until someone notices and re-imports a fix. Diffing the two exports first, with Handle or SKU as the key, turns "did that change apply correctly" from a guess into something visible on one screen before you click import. The same five-minute habit works whether the export came from Shopify, WooCommerce, BigCommerce, or Amazon.
Drop your before and after product or inventory exports in and see exactly what changed.
Try the CSV diff tool free →Picking the right column to match rows on matters more than which tool you use.
What is a match key? → →