Importing Discounts

The Discounts import creates and updates your store's discounts from a CSV/Excel file, a Google Sheet, or directly from another connected store. It covers the six discount types you can create yourself:

MethodTypeWhat it does
Code or AutomaticAmount off productsA percentage or fixed amount off specific products/collections.
Code or AutomaticAmount off orderA percentage or fixed amount off the whole order.
Code or AutomaticFree shippingFree shipping, optionally limited by country and a maximum rate.
Code or AutomaticBuy X Get YBuy a quantity of one thing, get another at a discount.

Code discounts need a code customers type at checkout; Automatic discounts apply on their own. App-managed discounts (created by another Shopify app) can't be imported — only the app that owns them can create them.

For the wizard itself — uploading, mapping, dry runs, schedules — see Importing into EcomSolo.

How discounts are matched

Rows are matched so that re-running the same file updates instead of duplicating:

  • Code discounts match by their Code.
  • Automatic discounts (which have no code) match by Title.

If a match exists it's updated; otherwise a new discount is created. The dry run shows the create/update split before anything is written.

The operation you pick in Step 1 decides how matches are treated:

  • Create — new discounts only; a row matching an existing code/title fails.
  • Update — existing discounts only; a row matching nothing fails.
  • Upsert (the default) — creates or updates as needed. Re-runs are safe.
  • Delete — permission-gated and irreversible; see Deleting discounts.

Columns

Only Title is always required. Code is required for code discounts, and amount/percentage types need a Value. Everything else is optional and only read when it applies to the row's type.

ColumnNotes
TitleThe discount's name (shown in Shopify admin). Required. Also the match key for automatic discounts.
MethodCode or Automatic. If blank, a row with a Code is treated as Code, otherwise Automatic.
TypeAmount off products, Amount off order, Free shipping, or Buy X Get Y.
CodeThe redeem code (e.g. SUMMER15). Required for code discounts; the match key. For multiple codes on one discount, list them ;-separated (WELCOME; WELCOME2; WELCOME3) — the first is the primary/match code, the rest are bulk-added (see Multiple codes on one discount).
ValueTypePercentage or Fixed amount.
ValueThe amount — 15 means 15% for a percentage, 10 means 10 in your currency for a fixed amount.
StartsAt / EndsAtWhen the discount is active (ISO date/time, e.g. 2026-07-01T00:00:00Z). Leave StartsAt blank to start immediately (new discounts only — updates keep the original start date). Leave EndsAt blank for open-ended.
UsageLimitTotal number of times the discount can be used.
AppliesOncePerCustomertrue/false.
UsesPerOrderLimitBuy X Get Y — how many times it can apply within one order.
MinimumRequirementTypeNone, Amount (minimum subtotal), or Quantity (minimum item count).
MinimumValueThe subtotal amount or item quantity for the minimum requirement.
CustomerSelectionTypeWho's eligible: All, Customers, or Segments (code discounts only). Blank means all customers on new discounts; on updates a blank column leaves the existing eligibility unchanged.
CustomerSelectionValuesFor Customers, customer emails (; separated); for Segments, segment GIDs.
AppliesToTypeWhat the value applies to: All, Products, or Collections.
AppliesToValuesProduct or collection handles (; separated), resolved on the target store.
BuyType / BuyValuesBuy X Get Y — the "buy" items: Products/Collections and their handles.
BuyQuantity / BuyAmountBuy X Get Y — the minimum quantity or minimum spend the customer must buy.
GetQuantityBuy X Get Y — how many items the customer gets at the discount.
CountriesFree shipping — country codes (US;CA) or * for the rest of the world.
MaximumShippingPriceFree shipping — only discount shipping rates up to this amount.
PurchaseTypeOne-time, Subscription, or Both. Leave blank for the default (one-time purchases). Subscription/Both require your shop to actually sell subscriptions — Shopify rejects them otherwise.
CombinesWithProductDiscounts / …OrderDiscounts / …ShippingDiscountstrue/false — which other discount classes this can stack with.

Common export headers map automatically: Discount Title → Title, Limit Total Times → UsageLimit, Applies To: Values → AppliesToValues, and so on (the Matrixify-style column names are recognised out of the box).

Products, collections, and customers

Applies-to products/collections and eligible customers are matched to the target store:

  • AppliesToValues / BuyValues are product or collection handles, looked up in the target store. Anything not found there is skipped (the discount is still created) — import your Products/Collections first so they resolve.
  • CustomerSelectionValues for Customers are emails, matched to target customers. Customer segments can't be matched across stores by name, so a Segments selection only forwards explicit segment GIDs.

Importing from another store

On the wizard's Source step, pick From another store to copy discounts from a connected store — no file needed. Code and automatic discounts of all four supported types come across, matched by code/title on the target; applies-to and eligibility references are re-resolved by handle/email. App-managed discounts are skipped. Combined with a schedule this becomes a recurring one-way discount sync.

Multiple codes on one discount

A single code discount can carry many redeem codes — one campaign, dozens or thousands of unique codes. Put them all in the Code cell, ;-separated:

Code
WELCOME; WELCOME2; WELCOME3
  • The first code (WELCOME) is the discount's primary code — it's created with the discount and is the match key for re-runs.
  • The rest are added to the same discount in bulk after it's created (Shopify processes these as a background job, up to 250 codes per batch, so very large code lists are added in chunks automatically).
  • The discount imports as created/updated as usual; the extra codes' outcome is reported as a note on the row (e.g. "2 additional redeem code(s) added"). If some codes are rejected — most often because a code is already in use on another discount (Shopify requires codes to be globally unique) — the row still succeeds and the note says how many were rejected.
  • Copying a multi-code discount from another store brings all of its codes across (up to the first 100 that EcomSolo has synced).

Duplicates and surrounding spaces in the list are ignored, so A; A ; b ; B becomes primary A plus one extra b.

Deleting discounts

Pick the Delete operation in Step 1 (permission-gated) and upload a file with just the identity column(s) — matching works exactly like updates: a Code for code discounts, a Title for automatic ones. (For a multi-code discount, the primary code identifies it.) No other columns are needed.

The dry run shows a red "Will delete N"; rows that match no discount are skipped (no-ops), so re-running the same delete file is safe. Deleting a discount permanently removes it from Shopify — this cannot be undone.

Results and freshness

Discounts you create or update take effect in Shopify immediately, and EcomSolo's Discounts dashboard refreshes within seconds of the run.

Sample file

A ready-to-run sample covering every case lives at features/importing/examples/discounts-sample.csv — one row per case: a code percentage-off-products discount, a fixed amount-off-order with dates + usage limit + customer eligibility, a code free-shipping discount limited to countries, a code Buy 2 Get 1 free, an automatic percentage-off-order, an automatic free-shipping to the rest of the world, an automatic Buy X Get Y on a collection, a minimal row, an edge row with a quoted comma in the title, and a multi-code row (three codes on one discount).

A focused multi-code sample — a few discounts each carrying several codes plus a single-code control — lives at features/importing/examples/discounts-multicode-sample.csv.

Notes and limits

  • Multiple codes per discount are supported — list them ;-separated in the Code cell (see Multiple codes on one discount).
  • App discounts aren't importable — only the owning app can create them.

Troubleshooting

Error in the reportWhat it means / what to do
row requires a TitleEvery row needs a discount name.
code discounts require a CodeA Code-method row is missing its redeem code.
amount/percentage discounts require a ValueAn amount/percentage type is missing its Value.
... already been takenA code already exists but wasn't matched from the index; re-run — the importer resolves it and updates.
Could not find all provided country codes in shipping zones defined for the shopFree shipping — the Countries codes must be countries your shop actually ships to. Add them to your shipping zones (Settings → Shipping) or use * for rest-of-world.
Could not find rest of the world in shipping zones defined for the shopFree shipping with * — the target shop needs a "Rest of world" shipping zone (Settings → Shipping). Add one, or list explicit country codes instead.

FAQ

Will re-importing create duplicates? No — code discounts match by code and automatic discounts by title, and the operation is an upsert, so re-runs update in place.

Some products in my discount weren't included. Those products/collections aren't in the target store yet. Import them first, then re-run.

Does it delete discounts? Only if you choose the Delete operation, which is permission-gated and irreversible — see Deleting discounts. The default Upsert only creates and updates.