Importing Products

This guide covers everything specific to Products imports: the columns you can use, how to lay out multi-variant products, and how to read the report when something goes wrong. For the wizard itself (sources, mapping, dry run, schedules), see Importing into EcomSolo.

Supported columns

The left column is EcomSolo's field name — what you'll see in the column mapper. The middle column lists spreadsheet headers that are recognized automatically, including the headers Shopify's own product CSV export and other common bulk import/export tools use. If your header isn't listed, no problem: auto-detect suggests the closest match, and you can always pick the field manually.

Product fields

EcomSolo fieldRecognized CSV headersNotes
HandleHandleThe product's unique URL handle — used to match existing products. Required (or Title).
TitleTitleRequired when creating a new product.
DescriptionHtmlBody (HTML), Body HTML, DescriptionHTML is passed through; plain text works too.
VendorVendor
ProductTypeType, Product Type
StatusStatusACTIVE, DRAFT, or ARCHIVED (any casing — it's upper-cased for you). Leave empty to keep the existing status.
TagsTagsComma-separated list; spaces around commas are trimmed.
Option1 NameOption3 NameOption1 Name etc.The option's name (e.g. Size). Put it on the product's first row only.

Variant fields (one per variant row)

EcomSolo fieldRecognized CSV headersNotes
Variants.Option1Variants.Option3Option1 Value, Option2 Value, Option3 ValueThe option value for this variant (e.g. S, M, L).
Variants.SkuVariant SKU
Variants.PriceVariant PriceDecimal, e.g. 19.99.
Variants.CompareAtPriceVariant Compare At Price
Variants.BarcodeVariant Barcode
Variants.InventoryPolicyDENY or CONTINUE (sell when out of stock).
Variants.Taxabletrue / false (also accepts 1, yes, y).
Variants.InventoryItem.SkuSKU on the inventory item.
Variants.InventoryItem.Trackedtrue / false — whether Shopify tracks inventory for this variant.

Inventory columns (stock rides the product rows)

You can set stock levels directly from the Products sheet — no separate inventory file needed. All quantity columns apply after the product row lands, so a single file can create a product and stock it in one run.

Column headerWhat it does
Variant Inventory Trackershopify turns inventory tracking on for the variant; a blank cell turns it off. Not a boolean — don't use true/false.
Variant Inventory QtyAbsolute available quantity. Works on single-location stores — multi-location stores get a row error pointing to the per-location columns.
Variant Inventory AdjustAdds/subtracts from available (single-location stores).
Inventory Available: <Location Name>Absolute available quantity at that location.
Inventory Available Adjust: <Location Name>Delta on available at that location.
Inventory On Hand: <Location Name>Absolute on-hand quantity at that location.
Inventory On Hand Adjust: <Location Name>Delta on on-hand at that location.

Rules worth knowing:

  • Blank cells are skipped — a blank never zeroes stock, it leaves that location untouched.
  • Don't set and adjust the same thing on one row — an absolute column and its Adjust twin for the same quantity/location is ambiguous and fails the row (naming both columns).
  • Pick Available or On Hand per variant/location, not both — Shopify links the two measures (on hand = available + committed + unavailable), so setting both in one row is order-dependent: whichever writes second recomputes the other. With nothing committed they're the same number anyway.
  • Rows that stock a variant need its Variant SKU — that's how the quantities find the right variant on multi-variant products.
  • Quantities need the variant to be tracked — pair them with Variant Inventory Tracker = shopify for new products.
  • If the quantities fail (say, an unknown location name), the report shows the row as failed with the product itself already created/updated — fix the column and re-run with Upsert; only the stock is retried.

Image fields

EcomSolo fieldRecognized CSV headersNotes
Files.OriginalSourceImage Src, Image URLA public URL to the image file. Shopify downloads and hosts a copy.
Files.AltImage Alt TextAlt text for the image.

SEO fields

EcomSolo fieldRecognized CSV headersNotes
Seo.TitleSEO TitleThe search-engine page title.
Seo.DescriptionSEO DescriptionThe search-engine meta description.

Multi-row products: variants and extra images

A product with multiple variants spans multiple consecutive rows that repeat the same Handle — exactly like a Shopify product CSV export:

  • Row 1 carries the product-level fields: Title, Vendor, Status, tags, description — plus the option names (Option1 Name, Option2 Name, Option3 Name).
  • Every row (including the first) carries one variant: its Option1 Value / Option2 Value / Option3 Value, SKU, price, and other variant fields.
  • Extra image rows — to attach more images than you have variants, add extra rows with just the Handle and the image columns filled in.
  • Keep a product's rows together — rows for the same handle must be consecutive.

Product-level values on continuation rows can be left blank; the first row's values win. A simple product with a single variant needs only one row and no option columns at all.

Custom columns

A few headers get special treatment when they match exactly:

HeaderWhat it does
TagsSplits the cell on commas, trims each tag, and drops empties.
StatusSets product status: ACTIVE, DRAFT, or ARCHIVED. Empty keeps the current status.
PublishedFriendly boolean: true / 1 / yes / y sets the product ACTIVE; any other non-empty value sets it to DRAFT; empty leaves it unchanged.
SEO TitleSets the search-engine title.
SEO DescriptionSets the search-engine description.
Metafield: namespace.keyWrites the cell value into that metafield. Example header: Metafield: custom.care_instructions.

You can add as many Metafield: … columns as you need — one per metafield.

How matching works (upsert by handle)

With the default Upsert operation, the Handle decides what happens to each product:

  • Handle exists in the store → the product is updated. Only the columns you mapped are changed; everything else on the product is left as-is.
  • Handle doesn't exist → a new product is created. New products must include a Title.
  • Row has neither Title nor Handle → the row is rejected and recorded in the report; the rest of the run continues.

This makes imports repeatable: run the same file twice and the second run simply updates — no duplicates. Create only, Update only and Delete match by handle the same way; see Choosing the operation for how each behaves.

Products reject Merge. Shopify's productSet treats a product's variants and options as the complete desired state — anything missing from the input is removed — so a partial-column Merge file could wipe variants. A Merge run is refused up front; use Upsert with full rows (or Update) instead.

Sample CSV (multi-variant)

Copy this into a file, save it as products.csv, and upload it as-is — every header auto-maps:

Handle,Title,Vendor,Type,Status,Option1 Name,Option1 Value,Variant SKU,Variant Price,Image Src
classic-tee,Classic Tee,Acme Apparel,Apparel,ACTIVE,Size,S,TEE-S,19.99,https://picsum.photos/seed/classictee/800/800.jpg
classic-tee,,,,,,M,TEE-M,19.99,
classic-tee,,,,,,L,TEE-L,21.99,https://picsum.photos/seed/classicteeback/800/800.jpg
solo-mug,Solo Mug,Acme Kitchen,Drinkware,ACTIVE,,,MUG-1,9.99,

What this creates:

  • Classic Tee — one product with a Size option and three variants (S at 19.99, M at 19.99, L at 21.99) and two images.
  • Solo Mug — a simple single-variant product with no options.

Ready-to-run copies live under features/importing/examples/ — including products-sample-multi-variant.csv, products-sample-3-rows.csv, and products-inventory-columns-sample.csv (the inventory columns in action).

Limits and caveats

  • Image URLs must be publicly reachable and point at an actual image file that Shopify can recognize (a standard image type — ideally with a file extension like .jpg, .png, or .webp in the URL). URLs behind logins, or links to pages rather than files, are rejected by Shopify at run time.
  • Gift card products can't be created via import — Shopify doesn't allow creating gift card products through this API.
  • Variant option combinations must be unique within a product — two rows with the same Option1/2/3 values for the same handle will be rejected by Shopify.
  • File limits — CSV or .xlsx, up to 100 MB and 50,000 rows. Excel reads the first worksheet only.
  • Not yet supported — uploading images as a ZIP, variant-level image assignment, and cost-per-item. (Per-location inventory quantities are supported — see Inventory columns above.)
  • The dry run can't check everything (image reachability, store-wide SKU uniqueness) — those surface in the report after the real run.

Deleting products

Pick the Delete operation in Step 1 (permission-gated) and upload a file with just the Handle column — each handle is matched exactly like an update:

Handle
classic-tee
solo-mug

The dry run shows a red "Will delete N" count; a handle that matches nothing is skipped (so re-running the same delete file is safe). Deleting a product removes it and all of its variants from Shopify permanently — this cannot be undone.

Troubleshooting the import report

After every run, download the report from the import's row menu. Filter the Status column to failed and read the Errors column. Common messages:

Error message containsWhat it meansFix
"Handle already in use" / "has already been taken"Something else already owns that handle — often two different products in your file using the same handle, or a re-run where the earlier create hadn't been picked up yet.Make sure each distinct product uses a distinct handle, and that variant rows for one product are consecutive. Then re-run — upsert will match correctly.
"source file not found"The import's source file could no longer be read at run time.Re-create the import by uploading the file again.
"file type is not supported for referencing"Shopify couldn't recognize an image URL as a supported file — usually a link to a web page, a redirect, or a URL without a recognizable image type.Use a direct, public link to the image file itself (e.g. ending in .jpg or .png) and re-run those rows.
"row requires at least Title or Handle"The row had neither field, so there was nothing to match or create.Add a Handle (updates) or a Title (creates) to the row.
"Title cannot be empty" (on a create)The handle didn't match an existing product, so this row is a create — and creates need a Title.Add a Title, or fix the handle so it matches the product you meant to update.

Because the report repeats all your original columns, you can fix the failed rows directly in the report file, delete the extra report columns, and re-upload it — the successful rows are safe to include thanks to upsert.

FAQ

Do I have to use the standard Shopify export headers? No. Any headers work — you'll just confirm the mapping in Step 3. The common export headers are simply recognized without any manual mapping.

Can I update just one field, like Price, without touching anything else? Yes. Map only Handle plus the columns you want to change. Unmapped fields are left untouched on existing products.

What does an empty cell do? For Status (and Published), an empty cell means "leave unchanged," not "clear." For other fields, test the behavior on a single product with a small file first — a dry run plus one-row import is the quickest way to confirm exactly what an empty cell does to that field.

Where do imported images come from? Shopify downloads each image from the URL you provide and hosts its own copy — your source URLs aren't referenced after the import.

Can I import metafields? Yes — add one Metafield: namespace.key column per metafield. Values are written as-is; make sure they match the metafield's type in Shopify.

Can I delete products? Yes — pick the Delete operation and upload a file of handles. See Deleting products. It's permission-gated and irreversible, and removes each product's variants too. Merge, however, is not supported for products.