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.
- Cart value: pick an operator (greater than, less than, between, and so on), then enter an amount.
- Products viewed: choose SKU or category, a session or 30-day window, and the list of products (typed in, or a LIST dataset).
- Purchase history: pick what you want to know, such as has purchased or lifetime spend greater than.
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.
| Operator | Matches when the cart total is… |
|---|---|
| Greater than | strictly above your amount |
| Greater than or equal | your amount or above |
| Less than | strictly below your amount |
| Less than or equal | your amount or below |
| Between | within 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.
| Setting | Options | Meaning |
|---|---|---|
| Operator | Has viewed any / Has not viewed any | Whether at least one of the visitor's viewed products is in your set |
| Match by | SKU / Category | Whether the set is product SKUs or product categories |
| Window | This session / Last 30 days | How far back to look. "This session" resets when the browser tab session ends; "Last 30 days" persists across visits on the same device |
| Products | A typed list, or a LIST dataset | The 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-productslist (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.
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.
| Operator | Matches when… |
|---|---|
| Has purchased | the visitor has at least one recorded order |
| Has not purchased | the 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 than | the visitor's total spend, net of refunds, is above your amount (project currency) |
| Order count greater than | the 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.
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 in50to100, a 250.00 cart ingte250.purchaser:trueorfalse, 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 recordsfalse, 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.