PrestaShop to Shopify: converting a product CSV export
PrestaShop's file format is European in every detail: semicolons, decimal commas, tax-excluded prices and combinations held in a separate entity. Each of those is a decision you have to make before importing.
Where the file comes from
In the PrestaShop back office go to Catalog → Products and use the Export button above the product grid. The importable column set is documented on the other side of the same feature, Advanced Parameters → Import, whose PrestaShop 8 documentation prints the expected header row verbatim:
"Enabled";"Name";"Categories";"Price";"Tax rule ID";"Buying price";"On sale";"Reference";"Weight";"Quantity";"Short desc.";"Long desc";"Images URL"
Those are the names this preset maps. Note that the export grid and the import field list do not always agree — the grid can emit extra columns and localised headers — so check your own header row in step 3 before trusting the auto-match.
Pitfall 1: semicolons, and a decimal comma inside them
PrestaShop delimits with semicolons, which is standard for European CSV and the reason the file looks like a single column when opened carelessly. Worse, the price cells then contain 79,00 — a comma as the decimal mark, inside a semicolon-delimited file, which is the one combination that parses without error and still means something different from what you expect.
This tool detects the delimiter from the file rather than assuming a comma, so the semicolon case loads correctly, and normalises money cells to Shopify’s required form: plain digits, a dot as the decimal mark, two places. 79,00 becomes 79.00. Shopify rejects the comma form outright with a “price is not a number” error, which is why this one is worth catching in the preview rather than in the import report.
Pitfall 2: Price excludes tax, and Shopify’s does not have to
PrestaShop’s Price column is the pre-tax price, with Tax rule ID naming the rule that adds VAT on the storefront. A 79,00 cell is therefore not what a customer pays.
Shopify has no per-product tax rate in the product CSV. It has a boolean Charge tax, an optional Tax code, and a store-level setting for whether your prices include tax. If your Shopify store is configured “all prices include tax” — the normal EU setup — importing the pre-tax number undercharges on every order. Multiply the column by your rate before importing, or switch the store setting. The Tax rule ID is a PrestaShop database id and is deliberately dropped: it will not match any Shopify or Avalara code.
Pitfall 3: Categories are numeric IDs
Categories holds something like 2,8. PrestaShop’s own docs are clear that “Categories are to be specified using their existing IDs”, separated by commas. They are row ids in your old database and mean nothing anywhere else.
Mapping them to Shopify’s Type gives you products whose type is “2,8”. The preset maps the column so nothing is silently lost, but you should replace the IDs with real names in the sheet first — export your category list to get the id-to-name pairs. Shopify collections, which is what PrestaShop categories really correspond to, are built in the admin after import and are not part of the product CSV at all.
Pitfall 4: combinations are a separate entity, so variants are not in this file
PrestaShop models variants as Combinations, and its import tool lists them as their own entity alongside Products, Categories and Brands. A product export therefore gives you one row per product with no option columns — the size and colour matrix lives in a different export entirely.
So a plain PrestaShop product export converts to single-variant Shopify products, and that is the file being described. If you need the variants you have to export Combinations too and join them to their products on Reference before loading the result here. This is the one place where the CSV route is genuinely more work than it looks.
Pitfall 5: Images URL is a list, and a protocol-relative URL will fail
Images URL holds the whole gallery, comma-separated, and PrestaShop’s docs note the importer can regenerate thumbnails from it. Shopify needs the first URL on the product’s first row and one extra row per remaining image, each carrying only the handle, Product image URL and an incrementing Image position.
The preset selects the split image list formula, so those extra rows are generated for you. Watch for protocol-relative URLs — //cdn.example.fr/x.jpg — which are common in themes and which Shopify cannot fetch, because it needs an absolute http:// or https:// address. The validator reports “//cdn.example.fr/ceinture-1.jpg” is not an http(s) URL rather than letting the import discover it.
What the preset maps
Name → Title, Long desc → Description, Categories → Type, Reference → SKU, Price → Price, Buying price → Cost per item, Quantity → Inventory quantity, Weight → Weight value (grams) with the kg conversion, Images URL → Product image URL with splitting, and Enabled → Published on online store. Status is draft, so a catalogue whose prices still need the tax decision cannot go live first.
Short desc. is not mapped: Shopify has one description field, and concatenating both would duplicate the opening sentence on every product page. On sale is dropped too — it is a flag, whereas Shopify expresses a sale as a lower Price with the old one in Compare-at price, which is a per-product decision rather than a column rename.
Before you upload to Shopify
- Import into a development store or a draft-status batch first. Set the default status to
draftin the tool and nothing goes live by accident. - Shopify caps a product CSV at 15 MB. Bigger catalogues are split into numbered parts, and a product is never split across two files.
- Overwriting existing products by handle is destructive: a blank cell can erase data that is currently there. Export your live products first if you are updating rather than creating.
Full column contract: the Shopify product CSV format, column by column. Nexum Gate is not affiliated with Shopify Inc.