Cart predicate language

Cart predicates are boolean expressions evaluated against the current resolved checkout context. A matching expression makes a rule eligible; it does not guarantee that the rule wins later discount, shipping, or gateway selection.

The full cart context is used by cart discounts, shipping methods, absolute and relative shipping-method rates, and payment gateways. A cart discount’s line-item target uses a smaller context documented separately below.

See Predicate language first for the common operators and authoring model.

Top-level cart fields

FieldTypeNotes
customercustomerAlways present; its strings are empty for an anonymous cart.
shipping_addressaddress or nullGuard against null before reading nested fields.
billing_addressaddress or nullGuard against null before reading nested fields.
totalmoneyCurrent cart total.
subtotalmoneyCurrent cart subtotal.
currency_codestringCart currency, for example EUR.
storestoreStore context.
price_channelprice channelPrice-channel context.
line_itemscollection of line itemsSupports .any(...), .Contains(...) where applicable, and .count().

Customer, address, and money fields

Customer

  • customer.id
  • customer.email
  • customer.group
  • customer.groups

Thor evaluates the full cart predicate once with an empty customer.group, then once for every group the customer belongs to. This preserves simple rules such as customer.group == "cusgrp_...". Prefer customer.groups.Contains("cusgrp_...") in new predicates because it expresses membership directly.

For anonymous carts, customer.id and customer.email are empty strings and customer.groups is empty; customer itself is not null.

Money

Both subtotal and total expose cent_amount and currency_code. Amounts are integer minor units and should normally be paired with a currency check when a rule can run in more than one currency.

Shipping and billing addresses expose the same fields:

FieldFieldField
first_namelast_nameemail
phonecompanyaddress1
address2cityzip_code
provincestatecountry_code

Country codes are stored as ISO 3166-1 alpha-2 strings such as DK and DE.

Code in typescript

Store and price channel

  • store.id is a typed store ID with the store_ prefix.
  • price_channel.id is a typed channel ID with the ch_ prefix.
  • If either context value is absent, its id is an empty string rather than null.
Code in typescript

Line-item fields

Each entry in line_items exposes:

FieldType / nested fields
line_item_idCart line-item ID (cli_...)
currency_codestring
quantityinteger
amount.unit_pricecent_amount, currency_code
amount.original_unit_pricecent_amount, currency_code
variantid, name, sku, weight_in_kg
productid, name, tags, categories, collections

Each entry in product.categories and product.collections exposes id. Weight is a decimal number of kilograms. Unit prices are integer minor units.

Code in typescript

Line-item target predicates

A cart discount can target selected line items with the predicate on LineItemTargetInput. This predicate is evaluated directly against each line item.

Therefore the root fields are line_item_id, currency_code, quantity, amount, variant, and product. Do not start with line_items.any(...); Thor is already iterating the cart’s line items. Give the target an explicit predicate. Use true when every line item should be eligible.

Typed ID prefixes in this context

ResourcePrefixExample
Customercus_cus_...
Customer groupcusgrp_cusgrp_...
Storestore_store_...
Price channelch_ch_...
Cart line itemcli_cli_...
Productproduct_product_...
Product variantvid_vid_...
Categorycat_cat_...
Collectioncol_col_...

See Typed IDs for the complete handling guidance.

Validation checklist

  • Use snake_case property names and ==, not = or ===.
  • Guard shipping_address and billing_address against null.
  • Treat strings as case-sensitive; use uppercase currency and country codes.
  • Compare monetary values in minor units and weights in kilograms.
  • Use real typed IDs returned by Thor and the correct prefix, especially ch_ for channels and vid_ for variants.
  • Test authenticated and anonymous carts, zero and multiple customer groups, missing addresses, and more than one line item.
  • Remember that a matching predicate only makes a rule eligible; discount grouping, priority, availability, and later checkout selection still apply.