Shopify ⇄ WooCommerce Product CSV Migrator
The two platforms do not just name columns differently — they store products differently. This converts the structure, translates the values it can prove, and tells you exactly what it could not carry over.
🔒 Your catalogue never leaves your browser.
The three things a column rename cannot do
1. Variants are a different shape
Shopify keeps a product together by repeating its Handle down consecutive rows. WooCommerce has no grouping column: the parent is one row of type variable and every variant is its own row of type variation pointing back through Parent. Since Shopify has no product-level SKU to point at, the parent here is given the handle as its SKU — stated in the conversion list rather than done silently.
2. Sale prices are stored the other way round
Shopify puts the current price in Variant Price and the crossed-out one in Variant Compare At Price. WooCommerce puts the crossed-out price in Regular price and the current one in Sale price. Rename the columns straight across and every discount in the catalogue silently disappears — the import succeeds, and everything goes back to full price.
3. Images live in different places
Shopify writes one row per image; WooCommerce expects them comma-separated in a single cell. Either way the URLs point at the source store, so the new store depends on the old one staying online until you re-host them.
Everything this conversion does (21 documented rules)
Structure: how products and variants are reshaped
MIG-S01 Handle groups become a variable product plus variation rows
Shopify keeps a product together by repeating its Handle down consecutive rows. WooCommerce has no such grouping: the parent is one row of Type "variable" and each variant is its own row of Type "variation" pointing back with Parent. The whole file has to be restructured, not renamed.
MIG-S02 Image rows collapse into one comma-separated Images cell
Shopify gives each image its own row (Image Src plus Image Position, with every other column empty). WooCommerce expects all image URLs in a single Images cell on the product row, in order. The conversion sorts by Image Position and joins them.
MIG-S03 Option columns become attribute columns
Option1/2/3 Name and Value become Attribute N name and Attribute N value(s). The parent row carries the full set of values joined with " | "; each variation row carries the single value it is pinned to.
MIG-S04 The variable parent gets a SKU derived from its handle
WooCommerce links a variation to its parent through the Parent column, which accepts a SKU or "id:123" — and an ID only exists after the import. Shopify has no product-level SKU at all (only variants carry one), so the parent row would have nothing to point at. The conversion therefore gives the parent the handle as its SKU: it is unique, it already identifies the product, and it is stated here rather than invented silently.
Fix: Keep it, or search-and-replace the parent SKUs for your own scheme before importing — each variation's Parent column must match whatever you choose.
MIG-S06 The derived parent SKU collided with a variant SKU
A variant in this file already uses the handle as its SKU, so using it for the parent as well would produce two rows with the same SKU — and WooCommerce rejects the second one. The parent falls back to the handle plus "-parent".
Fix: Rename either SKU in the source file if the generated one does not suit you.
MIG-S05 Single-variant products become simple products
A Shopify product whose only option is the default "Title / Default Title" is not a variable product — it converts to a plain simple product with no attributes, which is what it actually is.
Values: what gets translated, and how
MIG-V01 Sale prices are the other way round on the two platforms
Shopify writes the current price in Variant Price and the crossed-out price in Variant Compare At Price. WooCommerce writes the crossed-out price in Regular price and the current one in Sale price. A straight column rename therefore erases every discount: the file imports cleanly and every product quietly returns to full price.
Fix: This conversion swaps them: when Compare At is higher, Regular price takes Compare At and Sale price takes the current price.
MIG-V02 Weights convert between grams and the store unit
Shopify exports Variant Grams. WooCommerce takes a bare number whose unit lives in the header ("Weight (kg)") and comes from the store settings. The conversion divides by 1000 and names the unit in the header so the number cannot be read as grams by mistake.
MIG-V03 Booleans and status values are re-encoded
Shopify writes TRUE/FALSE; WooCommerce reads 1/0 and treats anything else as 0. Shopify Status (active / draft / archived) maps onto WooCommerce Published as 1 / -1 / 0 — archived becomes private rather than deleted, because a conversion must never remove products.
MIG-V04 Inventory policy becomes the backorders setting
Shopify's Variant Inventory Policy "continue" means "keep selling when out of stock", which is WooCommerce's Backorders allowed? = 1; "deny" is 0.
MIG-V05 Taxable flag becomes tax status
Variant Taxable TRUE/FALSE becomes Tax status taxable/none. Tax class is left empty so the target store's default applies — guessing a tax class is the kind of quiet mistake that only surfaces in an invoice.
MIG-V06 Barcodes are carried, but the importer will not map that column by itself
Variant Barcode holds the GTIN. WooCommerce has a native GTIN field, but it is not part of the default CSV mapping, so the column arrives and is ignored unless you map it on the import screen. The conversion carries the values rather than dropping them, and says so here.
Fix: On the WooCommerce import screen, map the "GTIN, UPC, EAN, or ISBN" column by hand.
MIG-V07 Handles become slugs, names become handles
Going the other way, WooCommerce has no Handle column: the conversion derives one from the product name (lowercase, hyphenated) and keeps it identical across a product and its variations, because that is what groups them in Shopify.
Columns with no equivalent
MIG-U01 Column has no equivalent in the target platform
The target platform has no core column for this data. It is listed rather than guessed at: writing it into an approximately similar column is how migrations end up with vendor names in the category tree.
Fix: Decide per column: keep it in a custom field ("meta:my_field" imports into WooCommerce), map it manually after import, or accept the loss.
MIG-U02 SEO fields belong to a plugin, not to WooCommerce core
SEO Title and SEO Description are Shopify core fields but WooCommerce stores them in whichever SEO plugin you use (Yoast, Rank Math, SEOPress), each with its own meta keys. There is no single correct target, so the conversion refuses to pick one.
Fix: Import the products first, then use your SEO plugin's own import to attach these fields.
MIG-U03 Per-market pricing columns are dropped
Shopify exports one column per market ("Price / International"). WooCommerce has a single price per product; multi-currency is a plugin concern. Those columns are dropped rather than flattened onto the base price.
Decisions only you can make
MIG-W01 Shopify allows only three options per product
WooCommerce products can carry any number of attributes; Shopify caps variant options at three. Attributes beyond the third cannot be represented as options and would silently disappear.
Fix: Merge or drop attributes down to three before converting, or keep the extra ones as plain product information.
MIG-W02 Product type and category do not correspond
Shopify has Type and Product Category (a fixed taxonomy); WooCommerce has Categories, a store-specific tree. They are different concepts, so mapping one onto the other is a decision about your catalogue, not a conversion.
Fix: Build the WooCommerce category tree first, then fill the Categories column — the format is "Parent > Child", comma separated.
MIG-W03 Images are referenced by URL, not copied
Both platforms take image URLs, so the converted file points at the original store's CDN. The import works, but the new store then depends on the old store staying online — and a Shopify store that is closed takes its images with it.
Fix: Download the images and re-upload them to the new store, or run the import while the old store is still live and re-point the images afterwards.
MIG-W04 Body (HTML) carries platform-specific markup
Shopify descriptions often contain classes, inline styles and shortcodes that mean something only in the old theme. WooCommerce imports the HTML verbatim, so the markup arrives intact and renders differently.
Fix: Spot-check a few descriptions after import; the description HTML checker lists the tags each platform strips.
MIG-W05 The file does not look like either platform export
Neither the Shopify column set (Handle, Title, Variant Price…) nor the WooCommerce one (Type, SKU, Regular price…) is recognisable in the header row, so there is no way to know what the values mean.
Fix: Export again from the source platform without renaming columns, or state the direction explicitly.