Guide7 min read2026-09-07

How to exclude products from discount codes on Shopify

ByViralPilot|Ecommerce SaaS agency, 8 years experience

Every Shopify merchant hits this one eventually. You launch a bundle at a price that already has the margin squeezed out of it, a customer finds last month's WELCOME15 code in their inbox, stacks it on top, and the order ships at a loss. You go into the discount editor to exclude the bundle. There is no exclude button.

This guide covers what the native editor actually offers, the workarounds merchants use and why they leak, and the checkout-level approach OfferGuard takes: when a protected product is in the cart, every applied code gets removed, whoever the buyer is.

What Shopify's discount editor can do

Shopify discounts are built around what a discount applies to, not what it avoids.

Applies to: products or collections

For "Amount off products" discounts, you choose specific products or specific collections. Anything not on the list is untouched. That is an inclusion list, and it works well when the discount is narrow.

For "Amount off order" discounts, there is no product selector at all. The discount applies to the whole cart. A percentage off the order is exactly the kind of code that lands on your bundle.

Combinations

Every discount has a Combinations setting: it can combine with product discounts, order discounts, shipping discounts, or none of them. This controls whether two discounts stack with each other. It does not control whether a discount applies to a specific product.

Minimum requirements and eligibility

You can require a minimum purchase amount or quantity, and you can restrict a code to specific customer segments. Neither of these looks at what is in the cart line by line.

Automatic discounts

Automatic discounts follow the same rules as codes, with one difference: a customer can only have one automatic discount and one code applied at the same time in most configurations. That limits stacking but does nothing to protect a specific product.

Where the native approach breaks

The "everything except" collection

The standard workaround is to build a collection that contains every product except the ones you want to protect, then point each discount at that collection instead of "entire order."

It works on day one. Then someone adds a new product and forgets to add it to the collection. Or a product discount and an order discount are both live and the order-level one still applies to the protected item because order discounts don't take a product list. Or you have twelve codes running and each one needs the same collection swapped in by hand.

Merchants have been asking for a cleaner answer for years. The community thread on discount codes working for all customers instead of specific groups is one version of the problem; the eligibility looks right in the editor and the checkout does something else.

Codes shared outside your control

Even a perfectly configured code leaks. Honey, Capital One Shopping, and RetailMeNot scrape codes and offer them to everyone at checkout. If a code exists, someone will try it on your protected product. The editor can't distinguish "this customer earned the code" from "this customer's browser extension found the code."

The bundle problem specifically

Bundles and multipacks are priced as offers already. The whole point is that the discount is baked into the variant price. Any additional code is a second discount on an item that has no room for it. What you want is not "exclude this product from code X" but "while this product is in the cart, no code works at all."

Shopify has no setting for that.

What OfferGuard does: discount exclusivity

OfferGuard checkout rules have an action called discount exclusivity. You turn it on for a rule whose trigger is the product, variant, or selling plan you want to protect. From then on, when a matching item is in the cart, the checkout extension removes every applied discount code.

How the removal works

The rule is evaluated server-side on every checkout. If any active rule with exclusivity turned on has its trigger products in the cart, the decision response tells the checkout extension that codes are not allowed right now.

The extension then walks the list of applied codes and removes each one through Shopify's checkout API. This runs whenever the applied codes change, not once. A code entered before the check, after it, or halfway through the shipping step is removed as soon as both facts are known: a protected product is present and a code is applied.

After removal, the buyer sees a short notice. The default text is:

Discount codes can't be combined with the offer in your cart, so the code was removed.

You can replace that with your own message, up to 300 characters.

Two scopes: contains and only

Scope decides how strict the cart match is.

Contains is the default. If the protected product is anywhere in the cart, codes are stripped, even if the buyer also has unrelated items. This is the right setting for a loss-leader bundle: you don't want a code discounting the rest of the order either, because the buyer will simply add a cheap item to unlock it.

Only is stricter about when it fires. Every line in the cart must match the trigger. Add one unrelated product and the codes are left alone. Use this when you are happy for codes to apply to regular items and only want to stop a cart that consists entirely of the protected offer from getting a second discount.

It applies to everyone

Exclusivity is a cart-presence check, not an identity check. It fires for new customers, returning customers, logged-in and guest checkouts alike. That is deliberate: the bundle price is already the offer, so nobody should stack on it.

This is separate from the identity side of OfferGuard, which decides whether a buyer qualifies for a new-customer offer in the first place. The two combine well. A rule can say: first-time buyers get this bundle at the intro price, returning buyers pay full price, and nobody applies a code on top.

Fail-open by design

If a code removal fails for any reason, the failure is logged and checkout continues. Exclusivity never blocks a purchase. The worst case is the same as not having the feature: a code stays applied. The buyer is never stuck.

Exclusivity versus gated-code rejection

OfferGuard has a second, different mechanism that is easy to confuse with this one.

Discount-code rules protect specific codes, for example a Bubblehouse referral code that should only work for a new customer. When the wrong buyer enters one of those codes, the code is rejected and the buyer sees why. That is about who may use a particular code.

Discount exclusivity is about what is in the cart. It does not care which code was entered or who entered it. Protected product present means no codes, full stop.

Most stores use both: exclusivity on bundles and intro offers, gated-code rules on referral and loyalty codes. The wholesale code pattern on the solutions page is a case where gated-code rules do the work; the bundle case is where exclusivity does.

Setting it up

  1. Open Checkout Rules in OfferGuard and create a rule, or edit the one that already protects your offer.
  2. Set the trigger to the product, variant, or selling plan you want to protect. Variant titles and product handles work too if you'd rather match by name.
  3. Turn on discount exclusivity in the rule's actions. Pick "contains" unless you specifically want the stricter "only" behaviour.
  4. Optionally write the notice the buyer sees when a code is removed.
  5. Activate the rule.

No theme edits, no collection maintenance, no per-code configuration. Add a new bundle to the trigger and it is protected the same way.

When you still need the native tools

Exclusivity is a blunt instrument on purpose. If your requirement is "code A applies to shoes but not socks, code B applies to socks but not shoes," the native product and collection selectors are the right tool, and they handle it fine.

Use exclusivity when the rule is about the cart, not the code: this offer is final, nothing stacks on it.

For the rest of the offer-protection picture, the features page covers identity checks, new-customer offers, and lifetime limits, and the limit one per customer guide explains why Shopify's native per-customer setting needs help of its own.

Try OfferGuard on your store.

Free plan available. No credit card.

Install free on Shopify