Blog·August 2, 2026

How to block discount codes on sale items in Shopify

Marked-down products taking discount codes on top is the most common margin leak in Shopify. Here's why it happens and two ways to stop it.

Say you mark a hoodie down from $60 to $40. That’s a decision. You looked at the margin, decided what you could give, and priced it.

Then someone applies WELCOME15 at checkout and takes another $6 off, and your decision quietly stops mattering. Multiply that by every sale item and every live code, and you get the number that surprises most merchants when they finally measure it: discounts landing on already-discounted products are usually the single biggest line in their unintended discount loss.

Why Shopify allows this

To Shopify, your sale price is just the price. The compare-at field draws the strikethrough on your storefront, but discount codes don’t look at it. A 15% code means 15% off whatever the price happens to be, marked down or not.

There’s no native setting to change this. Nothing in the discount editor says “skip sale items.” You can build a discount that only targets certain collections, but you can’t tell an order-level code, or a code from some other app, to keep its hands off your markdowns.

So the fix has to happen at checkout, which is where PromoLock works.

First, know what “on sale” means

Everything below runs on one definition: a product is on sale when its current price is below its compare-at price. $40 price, $60 compare-at, that’s a sale item. If the compare-at is empty or equal to the price, it’s not.

This has a practical consequence. If you end a markdown by raising the price but leave the old compare-at sitting above it, that product still counts as on sale. Clearing compare-at when a sale ends is worth making a habit.

The store-wide fix: block codes when sale items are in the cart

In PromoLock’s Controller there’s a switch called Lock Discount Usage On Sale Items. It applies to every code entered at your checkout, including codes created by other apps, and it has two modes.

Block if the cart has any sale item. One marked-down product anywhere in the cart and codes stop working. Maximum protection, but blunt: a customer buying one clearance sock with $200 of full-price stock also loses their code, and that’s a support email.

Block when sale items exceed a percentage of the cart. This is the one most stores actually want. Set the threshold to 50 and a mostly-full-price cart keeps its code, while a cart that’s mostly markdowns doesn’t. The percentage is measured on money, not item count, so it maps to what the cart actually costs you.

Either way, you write the rejection message the customer sees. “Discounts can’t be used on sale items” does fine. It’s honest, and honest messages generate fewer support tickets than mystery errors.

The per-discount fix: your own offers skip sale items by default

Discounts you create through PromoLock come with a safeguard called Skip on-sale items, on by default. The discount simply never applies to marked-down lines. No blocking, no error, the code just doesn’t touch those items.

If you only ever ran PromoLock-created discounts, this alone would close the leak. The Controller lock exists for everything else: your old native codes, the referral app minting unique codes, whatever’s still floating around inboxes from 2024.

Or don’t block at all

There’s a third option that deserves its own post, because for some stores it converts better: let codes work on sale items, at a lower rate you chose. Full-price items get 20%, sale items get 5%, one code, nobody’s checkout errors. If blocking feels too aggressive for your brand, read how to control discounts on sale items before deciding.

Check what it was costing you

PromoLock’s analytics has a report for exactly this: sale-item loss, computed from your order history. Most merchants who look are surprised. Turn the lock on, watch that line flatten over the next month, and you’ll know precisely what the hoodie math was doing to your margin.