Field notes
The Discount Ladder: Running Promotions Without Destroying Margin
August 4, 2026
A brand doing about $9M a year came to us with a clean-looking P&L problem. Revenue was up 14 percent year on year. Blended gross margin was down 5.2 points. Nothing had changed in COGS, freight had actually improved, and the ads team had held MER flat. The margin had simply drained out through the front door.
The audit took an afternoon. The welcome flow gave 15 percent off. The abandoned cart flow gave 10 percent off with free shipping. The loyalty programme gave silver members 10 percent off sitewide, permanently. There was a lapsed-customer winback at 20 percent. And a legacy automatic discount from a 2024 collab that nobody had turned off. Sixty-one percent of orders in the trailing quarter carried at least one discount. Nineteen percent carried two.
No single one of those offers was unreasonable. Nobody had approved a 25 percent sitewide sale. The brand had simply added one sensible promotion at a time over three years, and never built a structure that said which offers were allowed to exist at the same time, or what any of them cost.
TL;DR
- Discount depth is not a marketing decision, it is a volume commitment. At 45 percent gross margin, 30 percent off requires 200 percent more units just to break even on gross profit dollars.
- Rank your offers into a ladder from cheapest to most expensive, and make climbing a rung require evidence that the rung below failed.
- Stacking, not depth, is where most brands actually leak. Shopify permits five discount codes plus a shipping code on one order and 25 live automatic discounts.
- Generic public codes get scraped, republished and auto-applied by browser extensions. Unique codes cannot be, and they carry materially higher AOV.
- Promotion frequency damages pricing power faster than promotion depth. Two deep windows a year cost less than a permanent 10 percent that never turns off.
The arithmetic that should precede every promotion
The only number that matters when you approve a discount is the volume lift required to keep gross profit dollars flat. It is simple: required unit lift equals the discount percentage divided by (gross margin percentage minus discount percentage).
| Discount | 70% gross margin | 60% gross margin | 45% gross margin |
|---|---|---|---|
| 10% off | +17% units | +20% units | +29% units |
| 20% off | +40% units | +50% units | +80% units |
| 30% off | +75% units | +100% units | +200% units |
| 40% off | +133% units | +200% units | +800% units |
Read the bottom right cell. A brand at 45 percent gross margin running 40 percent off needs nine times the unit volume to end up where it started. That never happens. What happens is that the promotion pulls forward demand that would have arrived at full price, the revenue line looks acceptable, and gross profit quietly falls off a cliff.
Two adjustments make this worse in practice. The table uses gross margin, not contribution margin, so once you subtract pick, pack, freight, processing and returns, every cell gets harsher. And it assumes every incremental unit is genuinely incremental, which it is not. Some meaningful share of discounted orders would have converted anyway.
That is why promotional performance measured in ROAS is close to meaningless. If you have not already done this, work through break-even ROAS and MER versus ROAS first, because a promotion evaluated on platform-reported return will always look like a winner.
Build a ladder, not a calendar
Most brands organise promotions by date. That produces a calendar of events with no internal logic, where the January offer is 20 percent because last January was 20 percent.
Organise them instead by what they cost you, cheapest first, and treat each level as a rung you may only climb when the one below has demonstrably failed.
Rung 0 gives away no price at all. A free shipping threshold set above your current AOV, faster delivery, or financing. Baymard's checkout research, built on 25 rounds of usability testing and benchmarking of 344 leading sites, consistently finds extra costs at checkout to be the dominant abandonment driver, and puts the long-run cart abandonment average at 70.19 percent. Solving a shipping objection is not a discount, it is a checkout fix. Our checkout friction audit covers the rest of that surface.
Rung 1 gives away COGS rather than price. Gift with purchase, sampling, an extended warranty. If your gross margin is 60 percent, a $12 retail GWP costs you under $5 and never touches the price the customer memorises. This is the most underused rung in DTC and the one we push hardest.
Rung 2 is a unique, single-use code inside one triggered flow. Not a public code. Rung 3 is tiered cart value, where depth scales with basket size, so blended margin holds or improves as the offer gets richer. Bundles belong here.
Rung 4 is a sitewide percentage, which is genuinely expensive and should be capped at two or three windows a year. Rung 5 is terminal markdown on end-of-life inventory, which is an inventory decision, not a marketing one.
Stacking is the actual leak
Depth gets debated in meetings. Stacking never does, and it is where the money goes.
Shopify's discount system has three classes: product, order and shipping. They calculate in that sequence, so an order discount applies to a subtotal that a product discount has already reduced. A single customer can apply up to five product or order discount codes plus one shipping code on one order, and a store can have 25 active automatic discounts running simultaneously.
That is the ceiling, not the default, but the defaults are the problem. Every discount you create has a combinations setting, and teams routinely leave it permissive because a customer complained once. A 15 percent welcome code, a 10 percent loyalty tier and a free shipping code are three separate reasonable decisions that combine into a 25 percent order with free freight. On a 55 percent margin product with $9 of outbound shipping, that order is contributing single-digit margin.
Three controls, in order of value:
- Write a combination matrix before you build anything. Which classes may combine with which, decided once, documented, and applied to every discount you create.
- Set
combinesWithexplicitly on every discount rather than accepting a default. If you are running app-based or Shopify Function discounts, that field is part of the API surface and should be in code review, not in a settings screen someone toggles at 6pm on a Thursday. - Audit active automatic discounts monthly. The 2024 collab discount that nobody deactivated is not a hypothetical. We find one on roughly every second store we look at.
Unique codes beat generic codes, and it is not close
Seguno analysed 65,055 newsletters sent by Shopify brands between May 2024 and May 2025. Unique-code emails carried an average order value of $116.91, against $84.10 for generic codes and $111.10 for emails with no code at all. Average selling price showed the same pattern, with unique-code buyers reaching for materially more expensive products. Yet generic codes were roughly three times as prevalent as unique codes, and 83.8 percent of newsletters carried no code whatsoever.
Note the middle column. Generic codes produced lower AOV than sending no discount at all. That is the signature of a self-selecting audience: a public code attracts price-led buyers into small baskets and simultaneously discounts everyone who would have bought anyway.
There is a second reason unique codes win that has nothing to do with buyer psychology. A generic code is a string. Strings escape. Once WELCOME15 exists, it appears on coupon aggregators within days and browser extensions will surface it at checkout to customers who never subscribed to anything. The PayPal-owned Honey extension became the case study for how far this goes: litigation and reporting through 2025 documented extensions injecting themselves into the attribution chain at checkout, and Google tightened Chrome Web Store policy in response. Whatever you think of the affiliate dispute, the operational point stands: your generic codes are being distributed by parties you did not hire, to customers you did not target, at moments when the sale was already won.
Baymard's checkout guidance follows from this. Collapse the promo field behind a link rather than displaying it by default, so you do not send a converting customer off to Google, and auto-apply codes where you can. Their benchmarking finds the large majority of sites still fail to auto-apply.
Practically: make unique codes the default for anything sent to a list. Klaviyo generates them natively at the flow level, so your abandoned cart sequence and VIP segment offers can be unique without extra tooling. Reserve generic codes for genuinely public campaigns where the code is the creative.
Returns are a promotion cost nobody budgets
The NRF put the 2025 US return rate at 15.8 percent of retail sales, or $849.9 billion, with ecommerce specifically at 19.3 percent and 9 percent of all returns judged fraudulent.
Apply that to a discounted order. The unit went out at a reduced margin. It comes back carrying reverse freight, inspection labour, repack and, frequently, a markdown because it can no longer be sold as new. A returned full-price unit is a bad day. A returned 30-percent-off unit is often a net negative contribution event before you count the customer service time.
This is why any promotion evaluation window shorter than your returns window is fiction. If your average return lands 24 days after delivery, a BFCM promotion reviewed on 5 December is being scored on half its costs. Model promotions on contribution margin after returns, over a window that actually closes. Our notes on the DTC finance dashboard and returns policy design go deeper.
What to actually buy
You need three capabilities: issue and control offers, see margin per order, and enforce combination rules. Most brands over-buy the first and under-buy the second.
| Tool | Cost | What it is genuinely for | When it is the wrong choice |
|---|---|---|---|
| Shopify native discounts | Included | Codes, automatic discounts, explicit combination control, three discount classes | You need per-customer eligibility logic or offers keyed to external data |
| Shopify Functions (custom) | Dev time | Precise stacking rules, margin floors enforced in code, tiered logic | Under roughly $3M, where an app plus discipline is cheaper than maintaining code |
| Klaviyo | Free to 250 profiles, then scales by active profiles | Unique code generation inside flows, segmenting who is even eligible for an offer | You are using it as the system of record for promo economics. It reports revenue, not margin |
| Triple Whale | Free tier, then roughly $179 to $539 per month by plan and GMV | Blended margin visibility, seeing what promotions did to contribution rather than revenue | Small catalogues where a spreadsheet built off Shopify's own sales reports is honestly sufficient |
| Rebuy | Flat package fee plus usage priced on orders per month | Cart-level upsell and tiered value offers that raise basket instead of cutting price | You have not fixed your PDP or checkout yet. Upsell on a broken funnel is expensive decoration |
| Loyalty platforms | Typically $100 to $500+ per month at this revenue band | Structured earn-and-burn that replaces recurring percentage-off with points liability | Your tier thresholds are not modelled. See loyalty tier math |
The pattern we see repeatedly: a brand owns four apps capable of issuing discounts and zero systems capable of telling it what a discount cost. Reverse that ratio. The comparison in upsell and cross-sell apps is a useful companion.
Our take
Two positions, both of which get argument.
First: frequency damages pricing power faster than depth, so run fewer, deeper, harder-edged events rather than a permanent low-grade discount. The conventional advice is the opposite, that shallow evergreen offers are safer than big sales. The mechanism says otherwise. Customers form a reference price from what they routinely observe they can pay. A code that is always available becomes the price. A 30 percent event that runs twice a year and then genuinely ends does not, because the other 50 weeks supply the reference. The permanent 10 percent loyalty discount is the most expensive line item in most DTC promo stacks precisely because it is invisible in every campaign review. It never appears in a promotion post-mortem because it is not a promotion. It is just a 10 percent haircut on your best customers, forever.
Second: stop scoring promotions on incremental revenue and start scoring them on full-price sell-through. Incremental revenue is unfalsifiable in practice. You cannot cleanly observe the counterfactual, and every attribution tool will hand you a flattering number. Full-price sell-through rate, the percentage of units in a period sold with no discount applied, is observable directly in Shopify, cannot be gamed by attribution windows, and moves in the direction you care about. A brand whose full-price sell-through is falling quarter on quarter is losing pricing power, regardless of what the revenue line says. Put that metric on the weekly and watch how quickly the conversation about the welcome offer changes.
The counter-argument to both is that targeting solves this: personalise the offer, give discounts only to price-sensitive customers, and you keep the volume without the margin loss. McKinsey's work on promotion analytics supports the direction, finding that programmes targeting known regular shoppers return roughly three times the ROI of mass promotions. We agree with the finding and disagree with what most brands do with it. Targeting is a rung-2 and rung-3 capability. It does not make rung 4 cheap, and it does not repair a reference price you have already reset. Sequence it: fix the ladder structure and the stacking rules first, then add targeting on top. Personalising a broken promotional architecture just distributes the damage more efficiently.
One more thing on the calendar. If November is the only window where your deep discount lives, protect it properly. Shopify merchants did $14.6 billion over BFCM 2025 at an average order value of $114.70, up 27 percent year on year. That weekend rewards preparation, not depth. Our BFCM readiness audit is the operational checklist.
What to do this week
- Pull every active discount and automatic discount in your admin, list them in one sheet with owner, depth, start date and combination settings, and delete anything nobody can defend.
- Calculate the required volume lift for your three most-used offers using your real contribution margin, not gross margin, and take the results to whoever approves promotions.
- Switch your highest-volume email and SMS flow from a generic code to unique codes, and collapse the promo field at checkout behind a link.
- Add full-price sell-through rate to your weekly reporting, and set a floor you will not go below.
- Set a dollar budget for gross profit given away over the next 12 months, assign it to finance, and make every campaign draw down from that single pool.
If you want a second pair of eyes on where your margin is actually going, that is the kind of work we do on consulting engagements and growth retainers. Book a 30-minute call and bring your discount list, or send scope through the custom quote form if you already know what you need. If you would rather start smaller, the free audit will surface the obvious leaks before we speak.
Frequently asked questions
There is no universal safe depth. The number that matters is your gross margin. At 60 percent gross margin, 20 percent off needs 50 percent more units to hold gross profit dollars. At 45 percent margin, the same offer needs 80 percent more units. Run that arithmetic before you approve any promotion.
Test replacing it, not deleting it blind. A free shipping threshold plus a gift with purchase often captures the same first-order conversion without resetting the customer's reference price. If the replacement holds conversion within a point, you have permanently recovered the margin on every future first order.
Shopify lets a customer apply up to five product or order discount codes plus one shipping code on a single order, and up to 25 automatic discounts can be live at once. Set combinations explicitly on every discount rather than accepting defaults, and never leave clearance or gift card offers combinable.
Yes for anything sent to a list. Seguno's analysis of 65,055 Shopify brand newsletters found unique-code emails carried an average order value of $116.91 against $84.10 for generic codes. Unique codes also cannot be scraped, republished on coupon sites, or auto-applied by browser extensions.
Set an annual discount budget in dollars of gross profit given away, the same way you set a media budget, and make finance the owner. Every campaign draws down that pool. This forces trade-offs between the welcome offer, the loyalty programme and the November calendar instead of letting each one grow independently.
Returns on discounted orders. The NRF puts the 2025 ecommerce return rate at 19.3 percent of online sales, and a returned discounted unit costs you the reverse logistics, the restocking labour and the markdown, while having contributed a reduced margin in the first place.
One-page resource
Get the Small Store Revenue Checklist.
The 12 things that actually move revenue on a store under $50K a month, in the order we'd fix them. Delivered to your inbox.