Blog · · 8 min
How to raise average order value on a store you coded yourself
Average order value moves through four mechanics, and each one acts on a different share of orders: the quantity tier on the product page, the shipping threshold in the cart, the named complement above the totals, and the addition after payment. On a custom store all four are components, not subscriptions.
By uxgen
Average order value is the one number a small store can move without more traffic. It has four levers, they act at four different moments, and they compound because they act on different orders:
| Mechanic | Where it lives | Acts on | What it asks of the buyer |
|---|---|---|---|
| Quantity tiers | product page | every order, before a cart exists | a choice they were making anyway |
| Free-shipping threshold | cart | orders already near the threshold | one more item, framed as saving |
| Named complement | cart, above the totals | the confirmation moment | one tick, small amount |
| Post-purchase addition | after payment | orders already won | one tap, zero risk |
If you have none of them, build them in that order. The first acts on 100% of orders and asks for nothing extra, which makes it the cheapest thing you will ever build.
Why start with the quantity tier?
Because it is the only one of the four that operates before the buyer has decided how much to spend, rather than trying to change a decision already made.
A single price with a stepper asks: do you want this. A tier selector asks: how many do you want, and here is what each answer costs per unit. Those are different questions, and the second one has no "no" in it. The buyer who was going to buy one is now choosing between one, two and three.
The arithmetic below is a worked example, not a measurement — plug your own numbers in.
// A worked example. Substitute your own unit cost and mix.
const unit = 2400; // €24.00 sale price
const cost = 900; // €9.00 landed cost
const tiers = [
{ qty: 1, pct: 0 },
{ qty: 2, pct: 12 },
{ qty: 3, pct: 20 },
];
for (const t of tiers) {
const revenue = unit * t.qty * (1 - t.pct / 100);
const margin = revenue - cost * t.qty;
console.log(t.qty, (revenue / 100).toFixed(2), (margin / 100).toFixed(2));
}
// 1 24.00 15.00
// 2 42.24 24.24
// 3 57.60 30.60
Three units at a 20% discount still carries more than twice the gross margin of one unit at full price. That is the whole case for the mechanic, and it is arithmetic rather than persuasion. The failure mode is a discount curve steep enough that the top tier earns less margin than the middle one — worth checking before you pick the percentages, because it is easy to do by accident.

How do the four mechanics avoid colliding?
They collide when two of them ask for the same increment at the same moment. Three rules keep them apart.
One ask per screen. The product page asks about quantity. The cart asks about the threshold or the complement, never both in the same viewport. The confirmation asks about the addition. A buyer facing two upgrade prompts at once takes neither.
Downstream mechanics inherit upstream success. A buyer who took the three-unit tier arrives at the cart already past the shipping threshold, so the bar congratulates rather than nags. That is the intended interaction, not a wasted opportunity.
The complement is named, and it is not the same product. A cart offering "add one more of what you already added" after the product page offered exactly that is the store asking twice and getting quieter each time. The complement is a different object, chosen by use — the reasoning is in frequently bought together, done right.
What does this cost on a custom store?
Nothing recurring, and that is the structural difference from the app route.
On a hosted platform, each of these four mechanics is typically a separate app with a monthly fee, and several of the upsell apps in that category price per order rather than per month — you pay on orders the widget did not influence, which is the complaint that shows up most often in their public reviews. On a store you coded, they are four components in your repository.
| Rented widget | Component you own | |
|---|---|---|
| Cost shape | monthly, sometimes per order | one build |
| Removal | uninstalling can take page content with it | delete a file |
| Styling | their design system inside your page | yours |
| Data | leaves your store | stays |
| What breaks on theme update | unknown | nothing, it is your code |
The trade goes the other way too, and it is worth stating honestly: a rented widget exists this afternoon and a component you own does not. If you have never shipped any of the four, the fastest path to knowing whether they matter for your store is to build the tier selector, which is the cheapest, and look at the result before building the other three. The full comparison is in replace Shopify apps with code you own.
What is the measurement that tells you it worked?
Average order value alone will lie to you, because it moves when your traffic mix moves. Two numbers together do not:
type Order = { totalCents: number; items: number; createdAt: string };
export function weekly(orders: Order[]) {
const n = orders.length;
if (!n) return null;
const revenue = orders.reduce((s, o) => s + o.totalCents, 0);
return {
orders: n,
aov: revenue / n,
// The one that actually attributes: did baskets get FULLER,
// or did the expensive product simply sell more this week?
unitsPerOrder: orders.reduce((s, o) => s + o.items, 0) / n,
};
}
unitsPerOrder is the honest signal for these four mechanics, because all four work by adding items rather than by raising prices. If average order value rises and units per order does not, something else changed — a promotion, a channel, a seasonal product — and you are about to credit the wrong thing.
Watch the refund rate in the same window. A mechanic that raises the basket by pushing someone into a quantity they did not want shows up as returns four weeks later, and a return costs more than the margin the upsell earned.
What not to build
Three things that are commonly grouped with this list and do not belong in it:
- A countdown on the discount. If the tier discount does not actually expire, a timer next to it is a fabricated deadline. There is a legitimate version of that component and it is narrow — see a countdown timer that is honest.
- A pre-ticked complement. A tick the buyer did not make is not a sale, it is a refund with a delay. In the EU it also falls under the rules on unfair commercial practices.
- A minimum order amount. It raises average order value by removing small orders, which is not the same thing as earning more money.
The four that work all share one property: the buyer would still have bought something if they had said no.
If you want a coding agent to produce these as real components rather than as a stepper and a progress bar, that is what uxgen does — it hands Claude the commerce mechanics as HTML you own, with no per-order fee. The open ones are in the commerce kit, MIT.
FAQ
How do you increase average order value without discounting?
Three of the four mechanics involve no discount at all. The free-shipping threshold trades shipping you already absorb for a larger basket, the named complement in the cart adds a small related item at full price, and the post-purchase addition sells after the money has moved. Only the quantity tier gives up margin per unit, and it more than recovers it on total margin per order.
Which upsell mechanic should I build first on a custom store?
The quantity tier on the product page. It acts on every order rather than on the subset that reaches a threshold, it asks the buyer nothing they were not already deciding, and it is the smallest of the four to build. Everything downstream inherits its effect, because a buyer who took a larger tier arrives at the cart already past the shipping threshold.
How do I know the upsell actually worked?
Track units per order alongside average order value, over the same window, and watch the refund rate for the four weeks after. All four mechanics work by adding items, so if average order value rises while units per order stays flat, something other than your components moved the number.
Do I need an app to run upsells on my store?
Only if your store is on a platform whose native surfaces you cannot reach, such as the post-purchase page on a hosted checkout. On a store you coded yourself, all four mechanics are components in your own repository with no recurring cost, no per-order fee and nothing to uninstall.