xDiscount is on the Shopify App Store. Founding merchants lock in lifetime founder pricing.
Docs

Discounts

Conditions & Rules

The three xDiscount conditions, item quantity, cart value and inventory, how a row is negated, and why rows fold strictly from top to bottom.

What Conditions Do

The idea

A discount without conditions applies to every product you targeted, every time, for as long as it is Active and inside its schedule. Conditions narrow that. They are extra checks that have to pass before the discount is allowed to reduce the price.

Conditions live in the Conditions section, at the bottom of the discount form under Discount period. When a discount has none, the section reads:

No conditions. This discount applies whenever it is active and in schedule.

Conditions are optional, and most discounts never need one.

What conditions do not do. They do not choose which products get the discount, which is the Included products section. They do not set the dates a discount runs, which is Discount period. And they do not decide which discount wins when two of them match the same item, which is Priority, where the lowest number wins and only one product discount applies per item.

The three condition types

xDiscount offers exactly three conditions. There are no others, and none are hidden behind an upgrade. Every one of them is on every plan, Free included.

ConditionWhat it measuresFields you fill inDecided where
Item quantityThe total number of items in the shopper’s cart, every line added together, not just the products this discount targetsMinimum items, Maximum itemsAt checkout, on the live cart
Cart valueThe cart subtotal, in your store’s currencyMinimum cart value, Maximum cart valueAt checkout, on the live cart
InventoryThe stock level of one product variantMinimum in stock, Maximum in stockBy the app, before checkout. See below

Quantity and value look at the whole cart

Item quantity and Cart value both read the whole cart. A “buy 3 or more” condition is satisfied by three of anything in the cart, not three of the discounted product.

How many times each one can be used

Each condition can be used once. A discount can carry one Item quantity row, one Cart value row and one Inventory row, never two of the same. A type another row has already taken is still listed, greyed out and marked as already used, so you can see why you cannot pick it. Your own row’s current type is never greyed out.

When all three are in use, Add condition switches off and says so:

Every condition is already in use. Remove one to add a different condition.

Building Conditions

Adding a condition

1

Open a discount

Go to Discounts and open one, or click Create discount.

Go to the Conditions section

Scroll to Conditions, at the bottom of the form under Discount period.

Add a row

Click Add condition. The new row arrives pre-set to the first condition you have not used yet. Change it with the Condition dropdown if you want a different one.

Set the bounds

Fill in a minimum, a maximum, or both. Repeat for as many conditions as you need, up to three.

Save

Click Save. Nothing is written to your store until every row passes.

Each row is numbered and has a drag handle on the left, Reorder condition 1, Reorder condition 2, and so on. Drag rows to reorder them, because the order matters, and the section says so directly:

Configure the conditions a cart must meet for this discount to apply. Choose a condition type, then set its values. Each condition type can be used once per discount.

To delete a row, click the delete button at its top right, Remove condition 1. There is no confirmation step, and nothing else on the form is affected.

Changing a row's type clears its bounds

That is deliberate. 5 means five items under Item quantity, five units of your currency under Cart value and five units of stock under Inventory, so carrying the digit across would quietly save something you never typed.

Minimums and maximums

Every condition is a range, not a comparison. There is no “greater than” or “equals” picker. You give a lower bound, an upper bound, or both.

  • Both bounds are inclusive. Minimum items of 3 qualifies at exactly 3.
  • Both bounds are independent. Fill in only the minimum for an open-ended floor, or only the maximum for a ceiling.
  • 0 is a real bound, not an empty field. A maximum of 0 means exactly that.
  • You must fill in at least one of the two. Leaving both empty blocks the save with “Set a minimum, a maximum, or both.”
What you typeWhat it means
Minimum 3, maximum blank3 or more
Minimum blank, maximum 55 or fewer
Minimum 3, maximum 53, 4 or 5
Minimum 5, maximum 5Exactly 5

Cart value uses your store’s own currency field, so the amount is shown and typed in the currency you sell in. There is no currency picker, and no symbol is hardcoded into the form. Item quantity and Inventory are whole numbers.

Negating a condition

Each row has a Negate this condition checkbox. Ticking it flips that row only, so the discount applies when the condition is not met.

A negated Item quantity of “at least 5” qualifies carts of 0 to 4 items and rejects carts of 5 or more. Negation never leaks into the rows above or below it.

On an Inventory row the checkbox explains itself, because the row removes variants rather than judging a cart:

Skips the variants INSIDE the range instead of outside it.

So a negated Inventory row set to 5 to 10 discounts everything except the variants holding between 5 and 10 units.

Joining rows with and / or

The first row has no join control, because it starts the chain and there is nothing to join it to. Every row after it has a Join dropdown with two lowercase options, and and or.

Rows fold strictly from top to bottom. There is no grouping, no brackets and no operator precedence. Each row takes the result so far and joins the new row’s result to it. This is not ordinary boolean algebra, and the difference is real.

Take these rows:

#JoinCondition
1WhenItem quantity, minimum 2
2orCart value, minimum 100

xDiscount reads that as row 1 or row 2. Add a third row joined with and and it becomes ( row 1 or row 2 ) and row 3, not row 1 or ( row 2 and row 3 ). If you want a specific grouping, put the rows in the order that produces it when read top to bottom.

An Inventory row is always joined with and. Its Join dropdown is locked, with the reason printed beside it:

Inventory can only narrow the discount.

That is not a limitation being hidden. An inventory row works by removing variants from the discount’s reach before anything else is read, so “low stock or a big cart” could never mean what it says, because the shopper with the big cart would never reach the comparison. Under and, the control and the behaviour agree. Rules that arrive from a connected AI assistant are held to the same rule and refused with “Inventory narrows the discount, so it has to join with AND.”

A quick way to check your logic

Read your condition list out loud, top to bottom, adding each row to the running answer. If it sounds right that way, it is right. If you find yourself adding brackets in your head, reorder the rows.

The Inventory Condition, in Full

This one behaves differently from the other two, and the difference is worth two minutes of your time, because it changes what you can expect from it.

It applies per variant, never per product

Stock is counted per product variant. A t-shirt whose Small holds 0 and whose Large holds 40 has no single stock figure, and xDiscount never invents one. An Inventory condition with a minimum of 5 leaves the Large discounted and skips the Small, on the same product, in the same cart, at the same moment.

It is resolved by the app, not read at checkout

A Shopify discount function cannot read stock. The figure does not exist in what Shopify hands it at checkout, and the only other place a number could come from is the shopper’s own browser, which can be edited.

So xDiscount answers the question somewhere the number is real, on the server, before checkout. When it resolves an inventory condition it reads each targeted variant’s stock from Shopify, works out which variants fall outside your range, and writes that list of variants into the configuration on your products. At checkout those variants are simply not part of the discount any more. Nothing is re-checked in the cart.

When it is checked

The builder prints the cadence next to the row, and it is exact:

Checked per product variant when this discount syncs, and once a day after that. Variants outside the range are skipped until the next check.

In practice:

EventDoes stock get re-read?
You open the discount and click SaveYes, immediately, for every product it targets
The daily refresh runs at 03:00 UTCYes, for Active discounts that use Inventory or Skip products that are out of stock
A shopper adds to cartNo
An order drains the last unitNo
You restock in ShopifyNo

What that means when your stock moves during the day

The answer is a snapshot, and it can be up to a day old. Both directions are real, and neither is hidden from you:

  • A variant that sold out after the last check keeps the discount until the next one. If you set the condition to protect margin on low stock, it can run a little past where you wanted.
  • A variant you restocked after the last check stays skipped until the next one. Shoppers see no offer on it in the meantime.

The fix for both is the same, open the discount and click Save. That re-reads stock there and then, for every product the discount targets, and the answer is correct again from that moment.

When inventory is the wrong tool

If your stock turns over inside a single day, so flash sales, one-of-a-kind items, or a shop that restocks constantly, an Inventory condition is the wrong tool. Use it for slower decisions, like “stop discounting once we are down to the last 5”, rather than as a live gate.

Variants that do not track inventory

A variant with inventory tracking switched off reports no stock figure at all. Those variants are never skipped, whatever bounds you set. “0 in stock” and “not tracked” are not the same thing, and treating them as the same would quietly drop every digital product, service and untracked item out of your discounts.

The checkbox and the condition are the same mechanism

Skip products that are out of stock, in the Discount configuration section, is the special case “at least 1 in stock”. It is resolved at the same moments, from the same stock read, and it obeys the same rule about untracked variants. Its own help text on the form says “Checked at save time. Variants with no stock won’t be discounted.”, and the daily refresh covers it too.

Two inventory discounts on one product

If two discounts on the same product both use Inventory with different ranges, both obey the combination of the two, so the looser of the two skips more variants than it asked for. This keeps the configuration on a product inside Shopify’s 10,000-byte limit, and it errs towards discounting less rather than more. A discount that applies too narrowly is visible to you and reversible. One that applies too widely costs you money on every order.

Scheduling Is Not a Condition

There is exactly one place to put a discount on a calendar, and it is not the Conditions section.

Open the Discount period section and fill in Start date, End date, or both. Both bounds are inclusive whole days and each works independently, so a start with no end runs forever, and a start equal to the end is a legal one-day window. Underneath, the form says whose calendar it uses:

Dates follow your store’s timezone, not your own.

There is no date condition to add. The Condition dropdown offers Item quantity, Cart value and Inventory, and nothing else. Two controls writing one window is how a discount ends up with two answers about when it runs, so the window lives in Discount period only.

If you have an older discount with a date condition, it still works and it is still editable. That row shows as Date range (set in Schedule) with its From and To fields intact, and a line underneath:

New discounts set their dates in Schedule. This condition is kept so discounts saved earlier keep running as they were.

Nothing can be switched to that type, and a new row can never be one. Moving an old discount over is a two-minute job. Copy the dates into Start date and End date under Discount period, delete the condition row, and Save.

What Qualifies and What Does Not

One condition, Item quantity, minimum 3, maximum 5

Items in cartQualifies?Why
2NoBelow the minimum
3YesThe minimum is inclusive
4YesInside the range
5YesThe maximum is inclusive
6NoAbove the maximum

The same row with Negate this condition ticked flips every answer in that column.

Two conditions, Item quantity or Cart value

ItemsCart subtotalReading top to bottomDiscount applies?
5$40yes or noYes
1$150no or yesYes
5$150yes or yesYes
1$40no or noNo

Adding an Inventory row

An Inventory row does not appear in that table at all, because it is settled before the cart is read. Add Inventory, minimum 5, to the discount above and the variants holding fewer than 5 units are no longer part of the discount. The quantity and cart-value rows never get a chance to rescue them.

VariantStock at the last checkIn the discount?
Small2No, skipped until the next check
Medium5Yes, the bound is inclusive
Large40Yes
Digital download, not trackedNone reportedYes, untracked is never skipped

Things that never qualify

SituationResult
The discount’s status is Draft or ArchivedNever applies, whatever the conditions say
Today is outside the Discount period datesNever applies, because the period is checked before the conditions
The cart contains none of the products you targetedNever applies to that cart
The variant was skipped by an Inventory condition at the last checkNever applies to that variant until the next check
A Cart value condition on a store selling in several currencies, when the exchange rate cannot be readDoes not apply. xDiscount refuses rather than guessing the threshold
An unreadable date on an older date conditionDoes not apply

In every unclear case, xDiscount declines to discount. A discount that wrongly applies costs you money on every order. One that wrongly does not apply is visible to you and fixable in a minute.

What Shoppers See

The card and checkout read the same configuration

Once you have added the xDiscount offer block to your product template, the storefront offer card lists the conditions underneath the offer. The card is included on every plan, Free included. That list is not a second description written by hand. The card and the checkout discount read the same saved configuration, so what a shopper is told and what they are charged cannot drift apart.

Your conditionOn the card
Item quantity, minimum 3Buy 3 or more
Item quantity, minimum 3, maximum 5Buy 3 to 5
Item quantity, maximum 5Up to 5
Cart value, minimum 100Spend $100.00 or more
Cart value, minimum 100, maximum 250Spend $100.00 to $250.00
Cart value, maximum 250Spend up to $250.00
Inventory, minimum 5While at least 5 are in stock
Inventory, minimum 5, maximum 10While stock is between 5 and 10
Inventory, maximum 10While stock is 10 or fewer
An older date condition, from and to2026-11-27 to 2026-11-30
Any of the above, negatedNot: Buy 3 or more

Rows after the first carry their own connector, and or or, printed in front of them, in the order you arranged them in the admin.

An inventory line states your bound, not today's shelf

The card prints an Inventory condition even though checkout no longer evaluates it. That is on purpose, because the rule is still the reason an offer a shopper saw yesterday is gone today, and saying so is better than an offer that silently disappears. The figure in the sentence is your bound, never a live stock count.

Shoppers browsing in another currency

If a shopper is browsing in a currency other than your store’s, the card prints your own figure with your store’s currency code beside it, for example Spend 100 EUR or more, rather than converting it. Showing your number wearing their currency symbol would tell them to spend the wrong amount to qualify.

Conditions are never used to explain a failure at checkout. The label beside an applied saving is always the single word xDiscount. It never spells out mechanics, amounts, or which condition was missed.

Saving and Error Messages

Errors appear after your first click on Save, in red under the row that caused them. At the same time a banner headed This discount can’t be saved yet appears at the top of the page, and the toast “Fix the highlighted fields before saving.” appears.

MessageWhat to do
Choose a condition.Pick a type in the row’s Condition dropdown
That condition is no longer supported.Delete the row and add it again
Set a minimum, a maximum, or both.The row has both bounds empty
Bounds must be numbers.Remove any text from an Item quantity or Cart value bound
Minimum cannot be negative.Use 0 or higher
The minimum is above the maximum.Swap the two values
Stock levels must be numbers.Remove any text from an Inventory bound
Stock levels are whole numbers.Stock is counted in whole units, so remove the decimal
Stock cannot be negative.Use 0 or higher
Inventory narrows the discount, so it has to join with AND.An Inventory rule arrived from a connected assistant joined with or. The form never produces this
Set a start date, an end date, or both.An older date condition has neither date
Use a real date in YYYY-MM-DD format.Check the date actually exists on the calendar
The end date is before the start date.Swap them, or set them equal for a one-day window

Nothing is written to your store until every row passes.

Conditions cost space on each product

Conditions add to the size of the configuration xDiscount stores on each targeted product, and Shopify caps that at 10,000 bytes. An Inventory condition adds the list of skipped variants on top of that. If a save is refused for being too large, reduce the number of targeted variants or trim conditions and try again. The Targeting Products guide covers the limit in full.