Commerce Conditions

Commerce conditions let you target shoppers by what is in their cart, what they have been browsing, and whether they have bought from you before. They are condition types in the Audience Builder, so they combine with every other condition using the same AND/OR logic. "Visitors on mobile, with more than £100 in the cart, who have never purchased" is one audience.

There are three commerce condition types:

  • Cart value: how much is in the visitor's cart right now.
  • Products viewed: which products (or categories) the visitor has looked at, in this session or in the last 30 days.
  • Purchase history: whether and how much the visitor has bought before, based on your order data.
  1. Cart value: pick an operator (greater than, less than, between, and so on), then enter an amount.
  2. Products viewed: choose SKU or category, a session or 30-day window, and the list of products (typed in, or a LIST dataset).
  3. Purchase history: pick what you want to know, such as has purchased or lifetime spend greater than.
Project audiences only

Commerce conditions compare money amounts, so they need a currency context: the project's configured currency. They are available when building project audiences; organization-level audiences do not offer them.

Where the data comes from

Each condition type reads from a different place, and knowing which is which explains how fresh the data is:

  • Cart value and viewed products live in the visitor's own browser. The snippet keeps them in browser storage, updated the moment something happens: add to cart, view a product. They are immediate, but they are per-device: the same shopper on a different browser starts fresh.
  • Purchase history comes from a visitor profile. A vs B builds it nightly from the order data you already send (Shopify webhooks, avsb.track.purchase, or the server SDK). The snippet fetches the profile once per page load when an experiment needs it.

On Shopify stores with the A vs B app installed, cart value and product views are wired up automatically by the theme app embed. No code needed. On other platforms, your site supplies them with two small calls: avsb.track.cart and avsb.recs.trackView.

Cart value

Compares the visitor's current cart total against an amount you enter, in the project currency.

OperatorMatches when the cart total is…
Greater thanstrictly above your amount
Greater than or equalyour amount or above
Less thanstrictly below your amount
Less than or equalyour amount or below
Betweenwithin your range, inclusive at both ends

Things worth knowing:

  • A cart total of exactly 0 is a real value: "cart value less than 10" matches an empty-but-known cart. "No cart known yet" is different. If the snippet has never been told a cart total on this device, every cart value condition evaluates to false.
  • Cart totals are assumed to be in the project currency. If your store shows prices in multiple currencies, the comparison does not convert. A 100 EUR cart on a GBP project is compared as if it were 100 GBP.

Products viewed

Matches visitors who have (or have not) viewed certain products.

SettingOptionsMeaning
OperatorHas viewed any / Has not viewed anyWhether at least one of the visitor's viewed products is in your set
Match bySKU / CategoryWhether the set is product SKUs or product categories
WindowThis session / Last 30 daysHow far back to look. "This session" resets when the browser tab session ends; "Last 30 days" persists across visits on the same device
ProductsA typed list, or a LIST datasetThe set to check against

The viewed-products history is fed by the same product-view tracking the recommendation engine uses: automatic on Shopify, avsb.recs.trackView elsewhere. The snippet keeps up to 200 viewed products per window on the device, newest first. Viewing a product again moves it to the front rather than adding a duplicate.

Using a dataset as the product list

Instead of typing SKUs into the condition, you can point it at a LIST dataset: a named, versioned membership list managed on the Datasets page. This is how you compose conditions like:

Cart value greater than 100 AND has viewed any product on the vip-products list (this session)

The list lives in one place; update the dataset and every audience that references it follows, with no audience edits. The snippet checks the visitor's 10 most recently viewed products (in the condition's window) against the dataset.

A dataset with no live version never matches

If the referenced dataset has no live version (it was never activated, or it was archived), the condition evaluates to false for everyone. That applies to both operators. "Has not viewed any" does not silently become true for all traffic when its list disappears.

Purchase history

Targets visitors based on the orders A vs B has recorded for them.

OperatorMatches when…
Has purchasedthe visitor has at least one recorded order
Has not purchasedthe visitor has no recorded orders
Last purchase older than (days)the visitor's most recent order is older than the number of days you enter: also matches visitors who have never purchased (no purchase is "older" than any cutoff)
Lifetime spend greater thanthe visitor's total spend, net of refunds, is above your amount (project currency)
Order count greater thanthe visitor's number of orders is above your number

How the profile is built, and what counts:

  • Profiles are rebuilt nightly from your recorded orders. A visitor is matched by the same visitor ID the snippet assigns, so purchase history is per-device, like everything else the snippet knows.
  • A fully refunded order still counts as a purchase: "has purchased" stays true and the order still counts toward order count. Refunds do reduce lifetime spend, which is always net of refunds (and never below zero).
  • Orders recorded in a different currency than the project are excluded from the profile entirely (the same rule revenue metrics follow).
  • Profiles are kept for 90 days past the last nightly rebuild that included the visitor. If a store stops sending orders altogether, its purchase-history data ages out after 90 days.
Purchase history is up to 24 hours behind

Because profiles are rebuilt nightly, a visitor who purchased 10 minutes ago will not match "has purchased" until tomorrow. If you need to react to a purchase immediately, use a session-window condition instead. For example, combine "has viewed any product this session" with your conversion flow, or use a cart value condition. Session conditions update the instant the data arrives.

When the data is missing: conditions degrade to false

Commerce conditions are designed around one rule: targeting never blocks or breaks the page. When the snippet cannot know the answer, the condition evaluates to false and the experiment simply does not enroll that visitor:

  • Browser storage unavailable (for example some private-browsing modes): cart value and products-viewed conditions evaluate to false. Nothing throws.
  • Profile lookup fails or times out: purchase-history conditions evaluate to false for that page view. The snippet waits at most about 1.5 seconds for the lookup, in parallel with everything else it does at startup. Experiments without commerce conditions are not delayed at all, because the lookup only happens when a running experiment actually uses one.
  • Profile lookup succeeds but finds no profile: that is a real answer. This visitor has never purchased. "Has not purchased" and "last purchase older than" match; the other purchase-history operators do not.
  • Referenced dataset has no live version: both products-viewed operators evaluate to false (see above).

The asymmetry is deliberate. A failed lookup making "has not purchased" true would suddenly match your entire traffic, which is worse than briefly matching no one.

Results segments: cart band and purchaser

When a running experiment references any commerce condition, the snippet automatically records two extra segments for every enrolled visitor. The Results page can then slice by them:

  • cart_band: the visitor's cart total at exposure, bucketed (amounts in the project currency): none (no cart known), 0 (exactly zero), lt50 (under 50), 50to100 (50 to under 100), 100to250 (100 to under 250), gte250 (250 and up). Boundaries are lower-inclusive: a 50.00 cart lands in 50to100, a 250.00 cart in gte250.
  • purchaser: true or false, from the visitor profile. Recorded only when the experiment uses a purchase-history condition, since that is the only time the profile is fetched. A failed lookup records false, consistent with targeting.

These appear in the segment filter like any other automatic segment: no setup needed.

Server-side (feature flag) projects

The same three condition types work in feature-flag rules evaluated by server SDKs, but the server has no browser to read from. Your code supplies the data as evaluation-context attributes (cartValue, viewedSkus, viewedCategories, purchaseHistory). The behavior differs from the snippet in two documented ways. An absent purchaseHistory attribute makes all purchase-history operators false (including "has not purchased"), and dataset-list conditions always evaluate to false server-side. See Attributes (Feature Flags) for the full attribute reference.

Was this helpful?