Targeting & conditions

Matchers reference & comparison behavior

Exactly how each of the 12 matchers compares values — case-sensitivity, range bounds, empty-value rules, and the edge cases that explain "why didn't my rule match?".

Every condition rule is a selector (the cart or customer data to check), a matcher (how to compare it), and a value. The selector decides what gets compared; the matcher decides how. This page is the deep reference for the matcher half — the subtle comparison behavior that explains most "but my rule should have matched!" surprises.

For the list of selectors and which data each one reads, see the Condition selectors reference. For combining rules into groups and the filter-then-measure pattern, see Complex conditions & recipes.

The display names below are exactly what you see in the rule builder dropdown. Two matchers, a strict "greater than" and a strict "less than", exist in the engine but are not exposed in the UI — the builder only offers the "or equal to" variants. See the edge cases section at the end.

The 12 matchers

Each matcher below lists its display name, what it compares, the value types it applies to, whether the comparison is case-sensitive, and how the value field behaves when you pick it.

is equal to

  • What it compares: an exact match. Values are coerced to strings and compared with loose equality, so the number 50 and the text 50 are treated as the same.
  • Applies to: strings (tag, vendor, title, SKU, type), numbers (quantities), prices (subtotal, total, filtered totals), collections, and resources (product).
  • Case-sensitivity: case-sensitive for plain string comparisons. Summer does not equal summer.
  • Value input: a single text, number, currency, or resource field depending on the selector.

is equal to is the only string matcher that cares about letter case. Red will not match a Product vendor stored as red. If you are unsure how a value is capitalized in Shopify, prefer contains or starts with, which lowercase both sides before comparing. Note the Product tag exception: is equal to on a tag is case-insensitive (both sides are lowercased), so tag Red does match red.

equals any

  • What it compares: nothing specific — it is a wildcard. On the Product selector it matches if there is any line item in the cart.
  • Applies to: the Product (variants) selector only.
  • Case-sensitivity: not applicable — no string is compared.
  • Value input: the value is left empty for the Product wildcard. No specific variant needs to be selected.

On the Product selector, "any line item in the cart" is measured after the ignore-existing-offers filter runs. An item this same condition already auto-added doesn't count toward the wildcard.

is not equal to

  • What it compares: the inverse of is equal to — loose inequality on string-coerced values.
  • Applies to: strings (vendor, customer tag, attributes), numbers, prices, collections, and the country selector.
  • Case-sensitivity: mirrors is equal to — case-sensitive for plain string comparisons.
  • Value input: a single field matching the selector type.

is greater or equal to

  • What it compares: value ≥ your number, evaluated numerically.
  • Applies to: numbers (quantities, per-SKU quantity) and prices (subtotal, total, filtered totals).
  • Case-sensitivity: not applicable.
  • Value input: a number or currency field.

Both sides are parsed as numbers. If the value can't be parsed (it's blank or non-numeric), it falls back to 0 rather than failing loudly. A misconfigured "greater or equal to" rule with an empty box behaves like "greater or equal to 0", which almost always passes.

is less or equal to

  • What it compares: value ≤ your number, evaluated numerically.
  • Applies to: numbers and prices.
  • Case-sensitivity: not applicable.
  • Value input: a number or currency field. The same non-numeric → 0 fallback applies.

is between

  • What it compares: a numeric range. The rule passes when min ≤ value < max.
  • Applies to: prices (subtotal, total, filtered totals) — wherever a numeric range makes sense.
  • Case-sensitivity: not applicable.
  • Value input: two fields — a minimum and a maximum.

The lower bound is inclusive and the upper bound is exclusive. A range of 50100 matches a cart of exactly 50 but not a cart of exactly 100. To include 100, set the maximum a little higher, for example 50101. This single behavior is the most common cause of "the rule didn't fire at my round-number threshold."

On a multi-currency store, each bound converts independently. A 50100 range set in your base currency becomes (50 × rate) to (100 × rate) for a shopper checking out in another market's currency, unless you set explicit per-currency amounts.

starts with

  • What it compares: whether the value begins with your text.
  • Applies to: strings (tag, title, SKU, type, ref) and the promo code selector.
  • Case-sensitivity: case-insensitive — both the cart value and your text are lowercased before comparing. GIFT- matches a SKU of gift-001.
  • Value input: a single text field.

ends with

  • What it compares: whether the value ends with your text.
  • Applies to: strings (tag, title, SKU, type).
  • Case-sensitivity: case-insensitive — both sides are lowercased.
  • Value input: a single text field.

contains

  • What it compares: whether your text appears anywhere inside the value (a substring match).
  • Applies to: strings (tag, title, SKU, type, ref), the UTM selector, and the URL selector — which only supports this matcher.
  • Case-sensitivity: case-insensitive — both sides are lowercased.
  • Value input: a single text field (or a multi-value tag input on UTM).

does not contain

  • What it compares: whether your text does not appear inside the value.
  • Applies to: strings (tag, title, SKU, type, ref) and the UTM selector.
  • Case-sensitivity: case-insensitive.
  • Value input: a single text field.

does not contain only matches when your search text has length greater than zero. An empty "does not contain" box does not match everything — it matches nothing. This guard prevents a blank rule from silently passing every cart.

On the Product tag selector, does not contain inverts at the item level: a line item is excluded if any of its tags contains your search text. So "tag does not contain clearance" drops any product carrying a tag like clearance-2024, not just an exact clearance tag.

is not empty

  • What it compares: that the field has a value (a truthy check).
  • Applies to: strings — tag, SKU, type, ref. (It is not offered on Product title.)
  • Case-sensitivity: not applicable.
  • Value input: disabled — no value is needed, so the field is greyed out.
  • For tags: passes when the line item has at least one tag.

is empty

  • What it compares: that the field has no value (a falsy check).
  • Applies to: strings — tag, SKU, type, ref.
  • Case-sensitivity: not applicable.
  • Value input: disabled — no value is needed.
  • For tags: passes when the line item's tag list is empty.

Which matchers each selector allows

Selectors don't expose all 12 matchers. Each selector is wired to a fixed matcher group. The table below maps the internal groups to the selectors that use them, so you know exactly which options appear in the dropdown.

Matcher groupMatchers offeredSelectors that use it
Priceis equal to, is not equal to, is greater or equal to, is less or equal to, is betweenCart subtotal, Cart total (original price), Filtered products subtotal, Filtered products total
Numericis equal to, is not equal to, is greater or equal to, is less or equal toFiltered products quantity, Per-SKU quantity (validation)
Stringis equal to, ends with, starts with, contains, does not contain, is not empty, is emptyProduct tag, Product SKU, Product type
Product titleis equal to, ends with, starts with, contains, does not containProduct title (note: no is not empty / is empty)
Product vendoris equal to, is not equal toProduct vendor, Collection
Attributesis equal to, is not equal toCart attribute, Line item attribute
Customer tagis equal to, is not equal toCustomer tag
Resourcesis equal to, equals anyProduct (variants)
URLcontainsPage URL
UTMis equal to, is not equal to, contains, does not containUTM
Refis equal to, is not equal to, contains, does not contain, is not empty, is emptyRef
Promo codeis equal to, starts withPromo code
Specific countriesis equal to, is not equal toSpecific country
Per-SKU quantityis greater or equal to, is less or equal toPer-SKU quantity validation

The Product title group is deliberately missing is not empty and is empty — every product has a title, so those checks would be meaningless. The full String group (tag, SKU, type) keeps them because those fields can legitimately be blank.

Edge cases that trip people up

These are the behaviors that most often produce "why didn't my rule match?" tickets. Each one is real engine behavior, not a UI quirk.

Worked examples

Cart between $50 and $100

Use one rule: Cart subtotalis between → minimum 50, maximum 100.

Because the upper bound is exclusive, a cart of exactly $100 will not match. If you want $100 carts included, set the maximum to 101 instead. A cart of exactly $50 matches, because the lower bound is inclusive.

SKU starts with GIFT-

Use one rule: Product SKUstarts withGIFT-.

This matcher is case-insensitive, so it matches SKUs stored as GIFT-001, gift-001, or Gift-Card. Compare with is equal to, which would only match an exact, same-case GIFT- string.

Tag does not contain clearance

Use one rule: Product tagdoes not containclearance.

On the tag selector this excludes any line item whose tags include the substring clearance anywhere — so clearance, clearance-2024, and final-clearance are all dropped. Keep the value box filled; a blank "does not contain" matches nothing.

Troubleshooting

SymptomLikely causeFix
Rule with is between ignores the round top numberUpper bound is exclusiveRaise the maximum (e.g. 50101 to include 100).
is equal to on a SKU/vendor/title never matchesCase mismatch — is equal to is case-sensitive (except on Product tag, which is case-insensitive)Switch to contains or starts with, or match the exact stored case.
does not contain with a blank box matches nothingEmpty search value is rejected by designEnter the text you want to exclude.
is greater or equal to passes when it shouldn'tEmpty / non-numeric value falls back to 0Enter a real number in the value box.
is between never firesOne or both bounds failed to parse and defaulted to 0Re-enter clean numbers in both fields.

On this page