Complex conditions & recipes
Combine rule groups, filter-then-measure logic, multi-currency thresholds, and the edge cases that decide whether a campaign shows.
Most campaigns only need one or two simple rules. But conditions are powerful enough to express precise, layered targeting. This page explains how rules combine, the "filter then measure" pattern, and the edge cases that trip people up — with copy-and-adapt recipes.
If you're new to conditions, start with How conditions work and the Condition selectors reference first.
Two levels of AND / OR
A condition is built from rule groups, and each rule group contains rules. There are two independent connectors:
- Within a group — joins the rules in that group.
AND: every rule must match.OR: at least one rule must match.
- Between groups — joins the groups together (the condition's connector).
AND: every group must pass.OR: at least one group must pass.
This two-level structure lets you express things like "(product is in Collection A OR Collection B) AND (cart subtotal is over $50)" — one group for the product match, another for the spend check.
Filter then measure
This is the most important — and least obvious — behavior.
When a rule group matches on product rules (tag, SKU, type, variants, collection, vendor, title), it doesn't just pass or fail: it narrows the cart to the matching items, and the next group measures totals on only those items.
Group 1 filters the products
For example, a tag rule "product tag is summer" keeps only the summer items in the
cart and passes them forward.
Group 2 measures the filtered set
A second group with "filtered products quantity is 2 or more" then checks the count of just the summer items, not the whole cart.
So "buy 2 items from the Summer collection" is two groups joined with AND:
first the collection filter, then the quantity check on the filtered items.
Order matters. Put the product filter in the first group and the aggregate check (quantity, subtotal) in the second. If you measure before filtering, the totals apply to the entire cart.
What "subtotal" actually measures
| Selector | Measures |
|---|---|
| Cart subtotal | The cart total after discounts. |
| Original price | The cart total before discounts. |
| Filtered products subtotal | The discounted total of just the filtered items. |
| Filtered products original price | The pre-discount total of just the filtered items. |
If a shopper already has a discount applied, a "subtotal over $50" rule uses the discounted number. Use original price if you want to ignore discounts. For the exact value format each of these price selectors expects (including multi-currency amounts), see the Selector reference.
Ranges are inclusive-min, exclusive-max
The is between matcher treats the range as min ≤ value < max — the lower
bound is included and the upper bound is excluded.
A range of 50–100 matches a subtotal of exactly 50 but not exactly 100.
To include 100, set the upper bound a little higher (for example 50–101).
For the precise comparison behavior of every matcher — case-sensitivity, how "contains" and "does not contain" behave, and the empty-value rules — see the Matchers reference.
Multi-currency thresholds
Price rules (subtotal, original price, filtered totals) can hold a value per currency. When a shopper checks out in another market's currency:
- If you set a specific amount for that currency, it's used as-is.
- Otherwise the app converts your base amount using the market's exchange rate.
For "free shipping over $50"-style thresholds across markets, set the amount explicitly per currency where you want a round number (e.g. £45 rather than an auto-converted £39.72).
Important: not every rule works at checkout
Conditions are evaluated in two places, and checkout enforcement supports fewer rule types:
- Storefront widgets & the cart evaluate the full set of rules.
- Cart restrictions and automatic discounts run as Shopify Functions at checkout and only support a subset.
For example, a collection rule works perfectly in storefront widgets but is silently ignored by cart restrictions — swap it for a product tag rule when you need the same targeting enforced at checkout.
The full matrix of which selectors each runtime supports lives in Where each rule works — storefront vs checkout. Check it before you build any restriction or automatic-discount condition.
If a cart restriction or discount seems to ignore a rule, check that the rule type is supported at checkout. See the storefront-vs-checkout matrix and use a supported rule (e.g. product tag instead of collection) for checkout-enforced features.
Customer & marketing rules need a source
- Customer tag rules only match for logged-in customers — a guest has no tags, so the rule won't match.
- UTM and referrer rules read the URL the shopper arrived from. If they navigate away and back without the parameters, the rule won't match.
- Promo code rules match the code applied to the cart, by the code's internal ID — set them up from the promo-code triggers flow.
Empty-cart behavior
When the cart (or the filtered set) is empty, price rules behave intuitively: an
empty cart has a subtotal of 0, so "subtotal is 0 or more" passes and
"subtotal is less than $X" passes for any positive X. Quantity-based rules on an
empty set evaluate against 0.
Recipes
Related
How conditions work
The basics of display rules and matching.
Selector reference
Every rule, its data point, matchers, and value format.
Matchers reference
Exactly how each matcher compares values, with edge cases.
Storefront vs checkout
Which selectors work in widgets vs at checkout.
How features interact
Evaluation order and conflicts across features.
Promo code triggers — wildcards, privacy & health
How promo-code triggers match under the hood, prefix wildcards, privacy and timing, health warnings, and advanced recipes.
Market & customer-tag targeting in depth
Master the market and customer-tag campaign filters, including the three-state market behavior, multi-currency, and evaluation order.
