# Product CSV preflight

An **unlaunched MVP** for checking likely Shopify **product** CSV import problems. Open index.html in a browser, select **new products** or **updates**, and choose a comma-separated UTF-8 .csv file of at most 15,000,000 bytes. The browser reads the file locally; the page has no upload endpoint, external scripts, analytics, account, or store access. Findings include physical row numbers and can be downloaded as a CSV. A clear report is **not** an import guarantee: export a backup and run a test import in Shopify.

## Voluntary operator feedback

The [page](index.html#feedback) has a separate, optional form for an operator to describe an actionable pre-import finding, a failure the checker missed or could not verify, and an explicit **yes or no** to whether they would request a complete report for **$9**. Either observation field may be left blank, but the $9 answer is required to record a response. The answer is interest only: there is no report purchase or payment flow. The feedback form works without running the checker and does not alter checker findings.

Responses are saved in that browser's local storage when available; if storage is blocked, they last only until the page is closed or reloaded. **Download feedback summary** makes a plain-text file with every response recorded in that browser, including both observation fields and each $9 answer. There is no account, server submission, analytics, or feedback CSV upload. Each browser has its own responses; the page does not combine feedback from different devices. Operators choose whether and how to share the downloaded file. Do not enter raw catalog data, store details, or personal information. **Clear recorded responses** removes the saved entries from that browser, but cannot retract a downloaded or shared copy.

These are self-reported observations, not verified import outcomes or proof of demand. For the [five-operator experiment](operator-experiment.md), compare each shared summary with the operator's import error or preview or before-and-after export, record missed failures as well as useful findings, and count only distinct operators with actual evidence. A $9 “yes” is a request, not a sale.

## Supported format and rule audit

**Shopify guidance checked 2026-10-05.** [F] is Shopify's [product CSV format guide][F], [I] its [common import issues][I], [C] its [CSV file guide][C], and [P] its [product import guide][P]. The rules below describe the checker, including where Shopify's pages differ. Errors mean a likely format or import problem; warnings identify a risk that depends on store or import context.

| Material rule | Checker behavior | Official evidence |
| --- | --- | --- |
| CSV structure and encoding | Parses comma-separated rows, quoted commas and newlines, doubled straight quotes, UTF-8 BOMs, and row widths. Reports malformed quotes, missing data rows, and invalid UTF-8 in the browser. Accepts CRLF as well as Shopify's recommended LF line endings. | [F], [I], [C], [P] |
| File size | Browser rejects files above 15,000,000 bytes before checking. | [C] specifies a 15 MB product CSV limit. |
| Headers | Checks first-row headings, duplicates, spaces, and unknown names. Recognizes current English product columns, older aliases mapped in checker.js, dynamic market headings, current Google Shopping headings including "Google Product Category", common older "AdWords Grouping" and "AdWords Labels" headings, and product metafields in bare, named, and named-semicolon forms. Older aliases get a warning because Shopify maintains backward compatibility. Singular legacy "Barcode" maps to "Barcodes"; using both is an error. | [F] (format, current Google headings, markets, metafields, Collection exception, legacy compatibility, Barcode conflict); [I] (header errors). |
| Product identity | Requires "Title" for new imports; requires both "URL handle" and "Title" columns for updates. Checks the first product row's title, handle characters, missing handles on variant rows, and repeated titled handles. Later variant or image rows may omit "Title". | [F] (required columns, valid handles, row layout); [I] (missing title, repeated handle). |
| Variants and updates | Checks paired option names and values, option order, and duplicate option combinations within a handle. In update mode, any included variant column requires both Option1 columns even when its cells are blank; populated variant cells also require option values. | [F] (variant dependencies and overwrite effects); [I] (duplicate options); [P] (option-position conflicts). |
| Prices | Rejects nonnumeric, negative, currency-marked, and grouped prices in "Price", compare-at, cost, and market price columns. Warns on a blank product or variant price: [F] says it defaults to 0.00, while [I] describes a blank-price import error. Decimal precision is not capped because [F] gives no universal precision rule. | [F], [I]. |
| Product status and flags | Checks populated "Status" values (active, draft, archived). Accepts blank "Status" on new imports as the documented active default; flags it on updates to avoid an unintended change. Checks populated published, tax, shipping, gift-card, and market-inclusion flags for true or false. Shopify's [F] overview describes defaults for blank cells, while its Status row says a present column needs a value, so a store test import remains important. | [F] (column value lists, defaults, and overwrite effects). |
| Inventory, fulfillment, and weight | Checks deny/continue inventory policy, whole-number quantity, whole-gram weight, and a nonblank SKU for a named custom fulfillment service. Warns if a tracked row has a blank quantity: [F] documents a zero default, while [I] also documents a blank-quantity error. | [F], [I]. |
| Packed product size | When shipping is required, any packed size must include length, width, height, and a cm or in unit. A row with "Requires shipping=false" is exempt, including the unit check, because Shopify ignores packed-size values on that row. | [F] (all-four dependency and shipping exemption). |
| Market prices | Recognizes dynamic "Included /", "Price /", and "Compare At Price /" headings. A populated fixed market compare-at price needs a populated fixed price in that market. | [F] (market headings and fixed-price dependency). |
| Images | Checks populated product and variant image fields for an absolute HTTP(S) URL; warns on HTTP because Shopify's image guidance calls for publicly accessible HTTPS, while [I] mentions HTTP in one troubleshooting example. Checks positive whole-number image positions. It does not fetch images. | [F] (image URL and position, public HTTPS for multiple images); [I] (image URL failures). |
| Collection | Accepts Shopify's "Collection" exception and checks its 255-character maximum. | [F] (Collection exception and limit). |

## Known limits

- This is an English **product** CSV preflight, not an inventory, customer, catalog, or variant-metafield importer. Product metafield **headers** are recognized; their values and store definitions are not validated. Shopify does not support variant metafields in this CSV. [F]
- Market names, catalog configuration, existing handles and variants, option changes that would replace variant IDs, store currency precision, custom fulfillment services, multi-location inventory, category taxonomy IDs, and product/metafield references require store context. The checker cannot verify those, nor whether a remote image is reachable or meets Shopify's image limits. [F], [I], [P]
- The checker does not validate every optional column value or enforce Shopify's tag, barcode, image-count, SEO-length, or gift-card-creation limits. It does not predict defaults and overwrite effects for every blank cell. In particular, a blank optional column in an update can clear an existing value; omit columns you do not intend to change. [F]
- The header recognizer covers the documented current columns, common older AdWords headings, and mapped legacy aliases, not every historic or app-defined heading. A flagged heading may be one Shopify can map interactively. Shopify can also reject a structurally clear file for store-specific reasons. [F], [I]

The original good-products.csv and bad-products.csv preserve the MVP examples. valid-export.csv exercises variants, a separate image row, markets, metafields, inventory, and packed size. invalid-import.csv exercises several independent, row-specific risks. These are checker fixtures, not proof of a successful Shopify import.

## Store validation record (2026-10-05)

JARVIS has no Shopify store account, and this objective does not create one. The retained files below are ready for a future development-store test, but **no Shopify import has been executed**. They omit image columns so their test does not depend on example.com images. Shopify's [import guide][P] calls for a product-data backup before importing and a review of the import details after upload (checked 2026-10-05).

| Evidence item | New-product import | Existing-product update |
| --- | --- | --- |
| Retained import CSV | [validation/new-products.csv](validation/new-products.csv) | [validation/update-products.csv](validation/update-products.csv) |
| Store backup before import | Pending: export relevant store products and record whether either target handle already exists. | Pending: export `preflight-canvas-tote` and its variants immediately before overwrite. |
| Checker result (2026-10-05) | New mode: 3 data rows, 0 findings. | Update mode: 2 data rows, 0 findings. |
| Shopify preview before import | Pending: upload and capture before clicking Import products. | Pending: select overwrite, upload, and capture before clicking Import products. |
| Final product data | Pending: export the two imported products and compare fields. | Pending: export the updated product and compare fields and variant IDs. |
| Checker versus preview/result discrepancies | None assessed; preview and result are unavailable. | None assessed; preview and result are unavailable. |

The update target is the `preflight-canvas-tote` product in the new-product CSV. Before the update, verify its actual store handle, fields, option values, SKUs, and variant IDs against the post-create export. For the overwrite, compare every included and omitted column against that backup, then compare Shopify's preview and post-import export. Shopify says a blank included non-required field clears its prior value while an omitted field stays as it was; variant fields require matching option columns ([P], checked 2026-10-05).

Planned new-product results, **not observed**: `preflight-canvas-tote` should be a draft, unpublished product with Title `Preflight Canvas Tote`, Description `Reusable cotton tote, natural`, Vendor `Preflight Lab`, Tags `preflight, tote`, and Color variants `Natural` and `Black` priced `12.50` and `13.50`. `preflight-notebook` should be a separate draft, unpublished product priced `8.00`. Verify all fields, SKUs, and variant IDs in the store export before updating. Then select **Overwrite products with matching handles** for the update CSV; Shopify's preview and final export must establish whether each expected outcome below occurred.

| Update field | Planned input | Expected result from [P] and [F] |
| --- | --- | --- |
| URL handle | `preflight-canvas-tote` | Matches the backed-up product. |
| Title | `Preflight Canvas Tote Revised` on first row | Product title changes. |
| Description | `Reusable cotton tote, revised` on first row | Description changes. |
| Tags | `preflight, tote, revised` on first row; blank on the Black variant continuation row | The product's tags become `preflight`, `tote`, and `revised`. The blank continuation cell is intended to leave the first row's product-level tags in effect, not clear them. |
| Vendor | Column omitted | `Preflight Lab` remains. |
| Status and online-store publication | Columns omitted | Draft and unpublished values remain. |
| Option1 name and value | `Color` with `Natural` and `Black` on matching rows | Both variants remain associated with their original option values; compare variant IDs after import. |
| SKU | Original SKU on each matching variant row | `PFL-TOTE-NAT` and `PFL-TOTE-BLK` remain. |
| Price | `14.00` for Natural; `15.00` for Black | Each matching variant price changes. |

Shopify's variant-row instructions say to leave Tags blank after the first product row ([F], checked 2026-10-05), while its general overwrite guidance says an included blank field can clear an existing value. Treat the intended Tags outcome as a hypothesis until the store test: capture whether the preview shows the revised tags or omits tag details, then compare the final product tags in the export with `preflight`, `tote`, and `revised`. If the tags are blank or otherwise differ, record the observed values as a discrepancy, investigate the continuation-row behavior, and revise the CSV or checker guidance before calling validation complete.

Do not execute the planned update until its input CSV has been checked, a real store backup is retained, and its preview has been captured.

| Discrepancy | Evidence and disposition |
| --- | --- |
| Checker previously flagged an invalid packed-size unit even when `Requires shipping=false`. | [F] says packed-size values on that row are ignored and do not cause an import error (checked 2026-10-05). Fixed the unit check and added a regression test; this is a documentation-confirmed false positive, not a test-store finding. |
| Checker findings versus Shopify previews and final data | Comparison pending a development-store account and both imports. No store discrepancies are confirmed or dismissed. |

**Public free-site launch readiness: NO-GO.** The checker and retained CSVs pass local rule checks, but there is no preview or import result to establish how Shopify treats them in a live store. The separate public deployment gate remains open. The known format and store-context limits above still apply.

## Test

Run npm test here. It runs rule tests and a file-based Chromium smoke test at 390 × 844 and 1280 × 900 using preinstalled Playwright and Chromium; no package install or network access is required.

[F]: https://help.shopify.com/en/manual/products/import-export/using-csv
[I]: https://help.shopify.com/en/manual/products/import-export/common-import-issues
[C]: https://help.shopify.com/en/manual/shopify-admin/productivity-tools/csv-files
[P]: https://help.shopify.com/en/manual/products/import-export/import-products
