Import file reference
This is the field-by-field reference for Optionfier's import/export format: every Excel column, its JSON equivalent, accepted values, and what happens when you leave a cell blank. It assumes you've already read Importing and Exporting on the main docs page. If you're just backing up or moving your configuration between shops, start there instead.
Excel columns and JSON fields hold the same data; only the naming convention differs (column title vs. camelCase field). Leave an optional cell blank (or omit the field from JSON) to skip it:
- On a create row, the default in the table below applies.
- On a MERGE update row, the existing value is preserved (see What Stays the Same on Update).
"Required" means the field must be present on create rows; required fields on MERGE updates still fall back to the matched row's existing value if the file leaves them blank.
File-level Fields (JSON only)
Excel carries this information implicitly (shop and timestamp come from the workbook metadata on export). JSON has it as top-level fields.
| JSON field | Accepted values | Default | Notes |
|---|---|---|---|
version | 1 | N/A | Schema version. Always 1 today. |
exportedAt | ISO 8601 timestamp | N/A | When the file was exported. Informational. |
shopDomain | your-store.myshopify.com | N/A | Source shop. Informational: the importer writes into the current session's shop regardless. |
surface | options, inventory-only, bundles, build-a-box | required | Which kind of option set the file holds. Every group in the file must belong to this surface, or the whole file is rejected. A MERGE group whose ID or handle matches an existing group under a different surface is also rejected. A NEW group is never matched against existing groups, but its handle must still be unused in your shop. The file's surface fills in the discriminator a group omits: inventoryEngine: INVENTORY_ONLY on an inventory-only file, kind: BUNDLE on a bundles file, boxMode: true on a build-a-box file. |
groups | array of option sets | [] | The root option-set array. |
Excel doesn't have a surface field: the surface is the name of the sheet holding the data. Options exports write the Options sheet; inventory syncs write Inventory Only; bundles write the Bundles, Variants and Option Fields sheets described in Bundles workbook. Build-a-Box has no Excel form yet: it exports and imports as JSON only. The Inventory Only sheet also drops several columns that either don't apply to that engine or never reach the storefront on it: Inventory Engine, Set Label On Product, Set Label On Cart, Treat As Line Item Property, Show Component Pricing, Show Component Pricing Always, Derive Parent Inventory, and Option Price Override.
Option set fields
Each option-set row starts a new option set.
| XLSX Column | JSON field | Accepted values | Default on create | Notes |
|---|---|---|---|---|
Group Handle | handle | kebab-case slug, unique per shop | required | The anchor for MERGE matching. Handles are unique per shop. |
Command | command | MERGE, NEW, or blank | MERGE | Case-insensitive. Any unknown value is treated as MERGE. |
Group Name | name | any text | the handle, if blank | Merchant-facing display name. |
Product ID | productId | Shopify product GID (e.g. gid://shopify/Product/123) | N/A | Connects the option set to a product. The importer prefers GID over handle when both are set. |
Product Handle | productHandle | Shopify product handle (e.g. custom-tshirt) | N/A | Cross-store portability: used as a fallback when the GID doesn't resolve in this shop. |
Product IDs | productIds | Shopify product GIDs | N/A | Export only, for an option set that applies to several products. It replaces Product ID. In Excel the list starts on the option set's first row, one product per row; in JSON it is comma-separated. Importing a product list comes in a later version: the row imports with a warning, MERGE keeps the option set's current products, and a new option set is created disabled. |
Product Handles | productHandles | Shopify product handles | N/A | The handles of the same products, in the same order. A product with no stored handle is left out, so the two lists only line up row by row when every product has a handle. |
Group Enabled | enabled | true, false | true | false imports the option set as draft (won't render on the storefront). |
Group Position | position | number | 1.0 | Display order on the main admin list. |
Inventory Engine | inventoryEngine | NATIVE_BUNDLES, INVENTORY_ONLY | NATIVE_BUNDLES | The legacy value LINE_ITEM_PROPERTIES is still accepted so older files import: it is converted to NATIVE_BUNDLES with every option set in the group set to Text on order. INVENTORY_ONLY belongs in an inventory-only JSON file, where it is the default and the only accepted value; in an options file it is a surface mismatch and the file is rejected. The Inventory Only sheet has no such column. See How Options Appear, and Who Tracks Inventory. |
Include Parent In Bundle | includeParentInBundle | true, false | false | Only honoured when Inventory Engine is NATIVE_BUNDLES. |
Sold Out Entire Group | soldOutEntireGroup | true, false | true | Disable add-to-cart when any option is fully sold out. A blank cell on a create row gets the database default, true; option sets created in the admin start at false. |
Derive Parent Inventory | deriveParentInventory | true, false | false | When enabled, the app derives the bundle parent product's stock level from its components and writes it to Shopify (opt-in). |
Options Carrier Id | optionsCarrierId | blank, or parent-line | blank | Only applies to a standard Options group (not Bundles, Build a Box, or Inventory sync). Blank routes answers onto the order's bundle grouping (no separate line; they won't reach packing slips or Order Printer). parent-line puts them on the product's own order line instead. |
| N/A | id | Optionfier option-set ID | N/A | JSON only. Exports include it; the XLSX format intentionally omits it (option sets match by handle). |
Option fields
| XLSX Column | JSON field | Accepted values | Default on create | Notes |
|---|---|---|---|---|
Set ID | id | Optionfier option ID | N/A | Used for MERGE matching within an option set. Blank → create a fresh option. |
Set Handle | handle | kebab-case slug, unique within the option set | required | Referenced by visibility conditions in other options. |
Set Command | command | any string | N/A | Reserved for future use. Option-level commands are not read today; the option set's Command cascades to all children. |
Set Label On Cart | labelOnCart | any text | N/A | Required for NATIVE_BUNDLES and LINE_ITEM_PROPERTIES. INVENTORY_ONLY options can omit it. |
Set Label On Product | labelOnProduct | any text | the labelOnCart | Optional override for the storefront display. |
Set Enabled | enabled | true, false | true | Disable an option without deleting it. |
Set Position | position | number | 1.0 | Order within the parent option set. |
Set Required | required | true, false | false | When true, customers must fill in this field to add to cart. |
Display On Frontend | displayOptionsOnFrontend | true, false | true | When false, the option is hidden on the storefront. |
Treat As Line Item Property | treatAsLineItemProperty | true, false | false | The Appears as setting: true is Text on order (the option shows as text on the parent line), false is Bundle items. Only honoured when Inventory Engine is NATIVE_BUNDLES. An INVENTORY_ONLY option set is always Text on order whatever this column says. |
Collect Color Value | collectColorValue | true, false | false | For color-swatch sets: when true, the cart records the color's hex value next to the label (e.g. Medium (#8D6944)). Default records only the label. |
Dropdown Style | dropdownStyle | fancy, native | fancy | Only applies to Selectable options rendered as a dropdown. fancy is Optionfier's own styled dropdown; native is the browser's plain <select>. |
Variant Image Size | variantImageSize | sm, md, lg, or blank | blank (off) | Thumbnail next to each choice. On a Fancy dropdown sm is the default 20px row and larger values grow the open list; a Native dropdown ignores this column. |
Variant Image Position | variantImagePosition | leading, trailing | leading | Which side of the choice label the variant thumbnail renders on. |
Show Detail Card | showDetailCard | true, false | false | Applies to any dropdown, Fancy or Native, with a linked variant. Shows the selected variant's card below the dropdown. |
Detail Card Image Size | detailCardImageSize | sm, md, lg | md | Image size in the selected variant's card. Only used when Show Detail Card is true. |
Show Component Pricing | showComponentPricing | true, false | false | Shows the per-choice price next to each choice. |
Show Component Pricing Always | showComponentPricingAlways | true, false | false | Also show prices that equal the parent variant's price. |
CSS Class Enabled | cssClassEnabled | true, false | false | Master toggle for the custom CSS class. |
CSS Class | cssClass | CSS class name | "" | Custom class applied on the storefront. |
Placeholder Enabled | placeholderEnabled | true, false | false | When true, the option starts with nothing selected instead of pre-picking the first choice, on every display style. On a dropdown that renders as an empty placeholder row. |
Placeholder Text | placeholderText | any text | N/A | Wording for the placeholder row. Only applies to Selectable options rendered as a dropdown. |
| N/A | lowStockNoticeEnabled | true, false | false | JSON only, no XLSX column. Shows a "Only X left" notice on choices whose linked variant is running low. |
| N/A | lowStockThreshold | number or null | null | JSON only, no XLSX column. The stock level that triggers the low-stock notice. |
| N/A | maxPerLine | number or null | null | JSON only, no XLSX column. The most units of this product one cart line may hold, whether or not this option's choices are picked; checkout refuses lines over the cap. An out-of-range value is clamped to a usable cap rather than rejecting the whole file. |
Visibility Condition JSON | visibilityCondition | JSON object or null | null | See Visibility Condition JSON below. |
Quantity By Source JSON | quantityBySource | JSON object or null | null | Conditional-quantity rule: how many units of the linked variant this option consumes, driven by another option's answer. Same rule shape as visibilityCondition. |
Excel round-trips every field above except the three marked JSON only. An Excel export/import of an option set with low-stock notices, a threshold, or a per-line cap silently drops them. Use JSON if you need those fields to survive the round-trip.
Common choice fields
Every choice carries the fields below. The type-specific fields live in Option Config JSON in Excel and at the top level of the option object in JSON (see Option Types and Per-Type Fields next).
| XLSX Column | JSON field | Accepted values | Default on create | Notes |
|---|---|---|---|---|
Option ID | id | Optionfier option ID | N/A | Used for MERGE matching within a set. Blank → create a fresh option. |
Option Type | type | see types table below | required | Determines which per-type fields apply. |
Option Variant Product ID | variantProductId | Shopify product GID | "" | Connected component product. |
Option Variant Product Handle | variantProductHandle | Shopify product handle | N/A | Denormalised reference kept in sync by the products/update webhook. |
Option Variant ID | matchingVariantId | Shopify variant GID | "" | Connected variant under the component product. |
Option Price Override | variantPriceOverride | decimal string (e.g. "12.99") | null | Custom price for an option shown as Bundle items. Ignored under LINE_ITEM_PROPERTIES. |
Option Quantity | quantity | integer ≥ 1 | 1 | How many units of the connected variant this option consumes. |
Option Inventory Management Enabled | inventoryManagementEnabled | true, false | false | Per-option inventory tracking toggle. |
Option Config JSON | (top-level keys on the option) | JSON blob | {} | XLSX-only; holds per-type fields without a dedicated column. |
Option Types and Per-Type Fields
The Option Type value (or JSON type) is one of the following. Per-type fields below live in Option Config JSON in Excel and at the top level of the option object in JSON.
| Option Type value | What it renders as |
|---|---|
SelectableOption | Dropdown, radio, pill buttons, or product grid (picked via displayAs) |
CheckBoxOption | Checkbox, pill toggle, or switch |
TextOption | Text input (single- or multi-line) |
NumberOption | Numeric input or slider |
DateOption | Date picker |
TimeOption | Time picker |
FileOption | File upload |
ColorOption | Predefined color swatch |
ImageSwatchOption | Image swatch |
DynamicColorOption | Customer-chosen hex color |
LinkedVariant | Inventory link (for INVENTORY_ONLY inventory syncs; never shown on the storefront) |
StaticContentOption | Structural content (heading, paragraph, divider, or spacer), collects no answer |
SelectableOption (dropdown / radio / pill buttons)
| XLSX Column / JSON key | Accepted values | Default | Notes |
|---|---|---|---|
Option Value / optionValue | any text | required | The choice text shown to customers. |
Option Display As / displayAs | dropdown, radio, buttons, grid | dropdown | Render style. grid is the Product grid: a wrapping grid of image tiles. Keep the same value across every option in a set. |
Option Selected By Default / selectedByDefault | true, false | false | Pre-select this option on page load. At most one per set. |
CheckBoxOption
| XLSX Column / JSON key | Accepted values | Default | Notes |
|---|---|---|---|
Option Label / label | any text | required | The checkbox label shown to customers. |
checkedByDefault | true, false | required | Start checked when the page loads. |
displayAs | checkbox, buttons, switch | checkbox | Standard checkbox, pill-button toggle, or an accessible switch. |
TextOption
| JSON key | Accepted values | Default | Notes |
|---|---|---|---|
placeholder | any text | required | Grey helper text inside the field. |
multiLine | true, false | required | Single-line input vs. textarea. |
validationType | none, email, telephone, url | none | Pattern applied to the input. |
minLength | integer ≥ 0 or null | null | Minimum character count. |
maxLength | integer ≥ 1 or null | null | Maximum character count. |
NumberOption
| JSON key | Accepted values | Default | Notes |
|---|---|---|---|
placeholder | any text | required | Grey helper text inside the field. |
minValue | number or null | required | Minimum allowed value. |
maxValue | number or null | required | Maximum allowed value. |
step | positive number | 1 | Increment step. |
displayAs | input, slider | input | Plain numeric field, or a range slider using the same min/max/step. |
DateOption
| JSON key | Accepted values | Default | Notes |
|---|---|---|---|
includeTime | true, false | false | Combine with a time picker. |
minDate | YYYY-MM-DD or null | required | Fixed lower bound. |
maxDate | YYYY-MM-DD or null | required | Fixed upper bound. |
minDateRelative | { anchor, offsetDays } or null | null | Relative lower bound. |
maxDateRelative | { anchor, offsetDays } or null | null | Relative upper bound. |
specificDateRule | { mode, dates } or null | null | mode is "block" or "allow"; dates is an array of YYYY-MM-DD. |
dateRangeRule | { mode, ranges } or null | null | ranges is an array of { start, end } (each YYYY-MM-DD). |
dayOfWeekRule | { mode, days } or null | null | days is an array of integers 0-6 (0 = Sunday). |
Anchors for relative dates: today, startOfMonth, endOfMonth, startOfNextMonth, endOfNextMonth. offsetDays is an integer, positive for future, negative for past.
TimeOption
| JSON key | Accepted values | Default | Notes |
|---|---|---|---|
minuteStep | integer 1-60 | 15 | Minute granularity. |
use24Hour | true, false | false | 24-hour vs. 12-hour display. |
minTime | HH:mm or null | required | Fixed lower bound. |
maxTime | HH:mm or null | required | Fixed upper bound. |
specificTimeRule | { mode, times } or null | null | times is an array of HH:mm. |
timeRangeRule | { mode, ranges } or null | null | ranges is an array of { start, end } (each HH:mm). |
FileOption
| JSON key | Accepted values | Default | Notes |
|---|---|---|---|
acceptedTypes | array of MIME types or extensions (e.g. ["image/*", ".pdf"]) | required | File type restrictions. |
maxSizeMB | positive number | required | Max per file. Subject to Shopify's 20 MB limit (1 GB for videos). |
ColorOption (predefined swatches)
| XLSX Column / JSON key | Accepted values | Default | Notes |
|---|---|---|---|
Option Color Name / colorName | any text | required | Display name for the swatch. |
Option Color Value / colorValue | hex string (e.g. #FF5733) | required | The swatch color. |
ImageSwatchOption
| XLSX Column / JSON key | Accepted values | Default | Notes |
|---|---|---|---|
Option Image URL / imageUrl | URL | required | Source image for the swatch. |
N/A / optionName | any text | required | Display name for the swatch. JSON only, no XLSX column. |
DynamicColorOption (customer-chosen color)
No type-specific fields. Customers enter an arbitrary hex color at runtime.
LinkedVariant (inventory syncs)
| JSON key | Accepted values | Default | Notes |
|---|---|---|---|
scope | GLOBAL, PER_VARIANT | GLOBAL | GLOBAL = deduct for every trigger variant; PER_VARIANT = deduct only for the specific trigger variant below. |
triggerVariantId | Shopify variant GID | "" | Populated when scope is PER_VARIANT. |
triggerProductId | Shopify product GID | "" | Populated when scope is PER_VARIANT. |
LinkedVariant choices also use the common matchingVariantId, variantProductId, variantProductHandle, and quantity fields; those identify the variant being deducted.
StaticContentOption (heading, paragraph, divider, spacer)
| JSON key | Accepted values | Default | Notes |
|---|---|---|---|
kind | heading, paragraph, divider, spacer | required | Which element this renders as. |
text | any text | N/A | Heading or paragraph copy. Unused on divider/spacer. |
level | h2, h3, h4 | N/A | Heading only. The semantic level rendered on the storefront. |
size | sm, md, lg | N/A | Divider/spacer only. The vertical spacing scale. |
Visibility Condition JSON
The Visibility Condition JSON cell (XLSX) or visibilityCondition field (JSON) holds an object with this shape:
{
"action": "show",
"logic": "and",
"rules": [
{
"sourceOptionSetId": "set_abcd1234efgh",
"operator": "equals",
"value": "Large"
}
]
}| Key | Accepted values | Default | Notes |
|---|---|---|---|
action | show, hide | show | Whether the rule shows or hides this option. |
logic | and, or | and | Combiner across multiple rules. |
rules | array of rule objects | required | See rule fields below. |
Rule fields:
| Key | Accepted values | Default | Notes |
|---|---|---|---|
sourceOptionSetId | another option's Set ID in the same option set | required | The option whose value drives this rule. |
operator | equals, not_equals | equals | Comparison. |
value | string or null | required | The value to match against. null means "the source has any value" (useful with not_equals for "source is empty"). |
Bundles workbook
A bundles Excel file has three data sheets. Bundles holds one row per bundle, Variants holds one row per variant you sell, and Option Fields holds the bundle's option fields. The Bundle Handle column links them. Sheet names are matched without regard to case or surrounding spaces.
A component key is how a cell names a component product: its variant's SKU, or its variant ID (gid://shopify/ProductVariant/123). Exports write the SKU, or the variant ID when the variant has no SKU. On import every key is looked up in your store before anything else is checked:
- A key that matches nothing stops the import (
FILE-11). The message names the bundle and the key. - A SKU shared by more than one variant stops the import (
FILE-12). The message lists the matching variant IDs; put the one you mean in the cell instead. A shop with duplicate SKUs hits this when re-importing its own export.
Each component's price is re-read from Shopify on every Excel import, because the workbook has no component price column. A variant with a blank Price totals at today's component prices.
Bundles sheet
MERGE replaces a bundle's whole recipe, variants and bundle settings with what the file says. A blank cell on this sheet means the default below, not "keep what's stored", except for Bundle Name and Product ID, which follow the usual MERGE rules.
| XLSX Column | Accepted values | Default | Notes |
|---|---|---|---|
Bundle Handle | kebab-case slug, unique per shop | required | Links the three sheets. The anchor for MERGE matching. |
Command | MERGE, NEW, or blank | MERGE | As on the Options sheet. |
Bundle Name | any text | the handle, if blank | |
Product ID | Shopify product GID | blank | Leave blank on a new bundle; Optionfier creates the Shopify product. |
Status | published, unlisted, draft, or blank | published | Case-insensitive. |
Option 1 Name … Option 3 Name | any text | blank | The bundle's variant options. Fill them left to right; a gap is an error. No names means a fixed bundle with a single variant. |
Include Bundle Line | true, false | false | Puts the bundle product on the order as its own line. |
Bundle Line Price | price | 0.00 | Charged on that line, on top of the components. |
Options Carrier | a component key from this bundle, bundle line, or blank | blank | Which line carries option answers. Blank is the order's bundle grouping. |
Fee Components | comma-separated component keys | blank | Marks those components as fees. A SKU containing a comma can't be listed here; use its variant ID. |
Included / <Catalog> | TRUE, FALSE, or blank | blank | One column per market or B2B catalog. Blank leaves the bundle's place in that catalog as it is, unlike the other columns on this sheet. See Catalog prices and inclusion. |
Variants sheet
One row per variant you sell. A combination of option values with no row is imported as not for sale, and re-importing the file keeps it that way. A fixed bundle has exactly one row with the option value cells blank.
| XLSX Column | Accepted values | Notes |
|---|---|---|
Bundle Handle | a handle from the Bundles sheet | required |
Option 1 Value … Option 3 Value | any text | One per option name on the Bundles row. Each combination appears once. |
Variant ID | Shopify variant GID | Written by export. Leave blank when authoring by hand. |
Variant SKU | any text | The bundle variant's own SKU. |
Price | price | Blank charges the sum of the components. |
Compare At Price | price | |
Price / <Catalog> (<CUR>), Compare At Price / <Catalog> (<CUR>) | price, remove, or blank | Optional pair per market or B2B catalog. See Catalog prices and inclusion. |
Component 1, Component 1 Qty, Component 2, … | a component key, then a whole number | Add as many pairs as the widest row needs. A component a row doesn't list has quantity 0 on that variant. |
A component's quantity on the first row that lists it is its default quantity. A component at quantity 0 on every row isn't written by export, so it drops out of the bundle on re-import.
Catalog prices and inclusion
Add a column per market or B2B catalog to set a bundle's price there or choose which catalogs it appears in. The column names carry the catalog's title as it appears in Shopify. Titles match ignoring case and extra spaces.
- Prices go on the
Variantssheet as a pair:Price / Europe (EUR)andCompare At Price / Europe (EUR). The currency in brackets is optional. If you write it, it has to be the catalog's currency. A catalog whose title ends in brackets, likeWholesale (VIP), can be written without the currency. - A blank cell leaves that catalog's price alone.
removein a price cell removes the catalog price and its compare-at price.removein a compare-at cell removes only the compare-at price. A compare-at price needs a price in the same catalog on the same row. - Catalog prices need the row's own
Price. A blankPricemeans the sum of components. The sum and a custom price each apply to the row as a whole, not catalog by catalog, so give the row aPricebefore you set one for a catalog. See Pricing. - Inclusion goes on the
Bundlessheet asIncluded / Europe,TRUEorFALSE.Statuspublishes the bundle to your store.Includeddecides which catalogs it appears in. It needs the permission the bundle page asks for. A draft bundle joins its catalogs once it's published. - The import stops on a catalog column it can't use: one on the wrong sheet (
Includedbelongs onBundles,PriceandCompare At PriceonVariants), one that's almost right but misnamed (likePrice - Canada), or two columns for the same catalog, even when the cells are blank. - Catalog prices and inclusion show in Shopify within a few minutes of the import.
- Export writes price columns only for catalogs where a bundle has its own price, and
Includedcolumns only once the permission is granted.
Option Fields sheet
A bundle's option fields: engraving, gift wrap and the like. The columns are Bundle Handle followed by exactly the option and choice columns of the Options sheet (Option fields, Common choice fields), and the same values apply. The group-level columns (Group Handle, Command and the rest) aren't on this sheet; the Bundles sheet carries those. The sheet is optional. Leave it out or leave a bundle's rows off it and that bundle's existing option fields are kept on MERGE. An option field you do list replaces its stored choices with the file's rows, as on the Options sheet.
Fields Excluded from Export
A handful of DB fields are deliberately stripped during export and ignored on import. Including them in a hand-authored file has no effect:
variantPrice(choice): the live Shopify price, hydrated by theproducts/updatewebhook. Not merchant-editable.optionSetId(choice): a foreign key regenerated by the importer at commit time.parentInventorySnapshot(option set): live derived-inventory state, not merchant-editable.