For a merchant-configured version with tiers, per-market rules, and a progress bar, use the Rewards block, with no code. This is for when your rule is something the block can’t express.
The snippet
Paste into Cart settings → Custom script → Initialization, and set the two constants:How it works
reconcileGift describes the state the cart should be in, then makes at most one change to get there:
- Qualifies and the gift isn’t there →
addItemadds it. - Doesn’t qualify and the gift is there →
removeItemremoves it, by the line’skey. - Otherwise → do nothing.
cart_loaded (so a cart that already qualifies on page load gets the gift) and cart_updated (so it reacts to every change afterward). Because cart_loaded replays to late subscribers, this works no matter when your script runs.
Note that adding the gift raises the cart total, so a threshold near a product’s price can oscillate: adding a $0 gift is safe, but a gift with a price could push the cart above the threshold on its own. Keep the gift free, or compare against a total that excludes it.
Adapting it
Gate on item count instead of spend:context, which is available before the cart loads:
A line transform cannot hide a line’s quantity controls — its only setters are
setTitle, setVariantTitle, setHidden, and setInternalProperties. If a shopper changes the gift’s quantity, correct it from a cart_updated handler instead.Where to go next
- Rewards block: the no-code version, with tiers.
- Actions:
addItem,removeItem, and the rest. - Events: why the guards matter.