Cross sell and upsell at checkout: what actually lifts basket value
Most shops have a recommendations carousel that came with the theme, and almost none know whether it makes money. In this article I separate the four mechanics that get lumped together, place each one in the journey, work through the numbers for an invented Leeds hamper shop (including a free delivery threshold that can lose money), and set out what UK law now bans and how I build and measure all of it in Solidus.
Most shops have a recommendations widget, and almost none know whether it pays
The usual picture is a carousel at the bottom of the product page with four items from the same category. It came with the theme. Nobody has checked whether anyone clicks it, or whether the people who click it spend more in the end or simply wander off.
That is a waste, because the customer at your checkout is the one you have already paid to bring in and already persuaded once. Baymard Institute's collection of 50 studies puts the average documented cart abandonment rate at 70.22%, and among shoppers who were not just browsing, the most common reason for leaving was extra costs that were too high (40%).1 Whatever you add to the basket has to work with that fragility, not against it.
This article covers the four mechanics that are usually lumped together, where in the journey each one belongs, the maths that tells you whether it is working, the psychology that holds up in research, the tricks that are now illegal in the UK, and how I build all of it into a Solidus store. The running example is Northgate Hampers, an invented online hamper shop in Leeds at northgatehampers.example run by Priya. Every number for her shop is made up so I can show each step.
Cross sell, upsell, bundle and add on are four different things
People use "cross sell" and "upsell" as if they were the same, and then wonder why the upsell is not converting when what they built was a cross sell in the wrong place.
A cross sell is a different product that goes with the one being bought: a bottle of wine with the cheese hamper, a greetings card with any hamper. The customer's question is "do I also want this", and the answer depends entirely on whether the suggestion genuinely belongs with the first item.
An upsell is a better version of the same product: the large hamper instead of the medium one. The question is "do I want more of what I have already decided I want", which is an easy yes only when the extra value is visible at a glance and the extra price is moderate.
A bundle is a fixed combination sold as one item at one price, usually with a small saving. Priya's build your own hamper is a bundle with a twist: the customer picks the contents, the basket and the price band are fixed.
An add on is the small thing attached at the last moment: a gift message, next day delivery, a named delivery date. Low price, high margin, very little thought.
Each mechanic has its own place in the journey
The mechanic has to fit what the customer is doing at that moment, so I think about the journey in five places.
The product page. The customer is still evaluating. This is the home of the upsell (the medium and the large hamper side by side, with the difference spelled out) and of the cross sell that helps the decision. A useful companion panel filters by the item's attributes. On Northgate's vegan hamper it shows only vegan chocolates and a vegan wine, because a cross sell that contradicts the main item is not extra revenue, it is a complaint.
The moment of adding to the basket. The customer has just said yes. Most shops spend this moment on a green message that disappears. I replace it with a drawer: what you added, your total, two things that go with it, one click to add each, and clear buttons to keep shopping or check out. Nothing else.
The basket. The customer is reviewing. This is where a free delivery threshold belongs ("add £9 for free delivery"), along with the last companion suggestion and add ons such as a gift card. It is not the place to reopen the decision about the main product.
The checkout. The customer is paying, and with a 70% average abandonment rate this is the most fragile stage of the shop.1 The only things I allow here are add ons that are about delivery itself: a delivery date, a gift message, next day delivery. One unticked box each, which in the UK is also the law, as the section on what is now illegal explains.
After the purchase. The order is placed and the customer is relaxed. This is where the next order is won: a one click addition on the confirmation page before the parcel ships, a message a week later with something that goes with what was bought, a reminder when the occasion comes round again.
Why average order value is the wrong headline number
Every cross selling case study leads with average order value going up. That number is easy to move and easy to misread.
Suppose an aggressive pop up in the basket works and buyers spend 20% more. The interruption also puts some people off, and conversion falls from 2.5% to 2.2%. Average order value is up. Revenue per visitor has fallen. The shop has got worse and the dashboard says it has got better.
So the first number to watch is revenue per visitor (per session, if that is what your analytics reports), the ratio of revenue to visitors:
Here is the conversion rate (orders divided by visitors) and is the average order value. RPV moves when either part moves, and you cannot game it by trading one against the other. In the example above, before and after looks like a win, but only if those buyers really spend 20% more. If the extra spend is 10%, RPV ends up at , which is a loss.
The second number is the attach rate: of the orders that saw an offer, the share that took it. It describes the health of one placement. There is no universal benchmark worth quoting, so the useful comparison is the same placement against itself over time and against a holdout.
The third number, and the one almost nobody tracks, is contribution. Cross selling an item at a loss is not growth. The expected extra contribution of a placement is an expected value: the chance that an order takes the offer, times what it adds:
Here is the number of orders that see the offer, is the attach rate, is the average price of the added item and is the gross margin on that item as a share of its price (see percentages). I keep a margin field on every product in Solidus for exactly this reason and report lift in contribution, not revenue.
A worked example at Northgate Hampers
Priya's shop has 40,000 visitors a month, a 2.5% conversion rate and an £85 average order, with a 38% gross margin. That is 1,000 orders, £85,000 revenue and £32,300 contribution a month. Delivery costs the customer £4.95 below the free delivery threshold.
The drawer after adding to the basket. Suppose 9% of orders take a companion averaging £14 at a 45% margin, and the drawer costs nothing in conversion because it is not in the way:
With , , and , that is 90 extra items, £1,260 revenue and £567 contribution.
The free delivery threshold. This is the one that catches people out. A threshold works on the basket, but every order that tops up to reach it also stops paying the £4.95 delivery fee. Lewis, Singh and Fay studied an online retailer that had experimented with many shipping fee schedules and found that free shipping over a threshold was very effective at generating sales, but that the lost shipping revenue could make such promotions unprofitable.2 The contribution per order that tops up is:
Here is the average amount added to reach the threshold, is the margin on what is added and is the delivery fee the shop no longer collects (the logic of marginal versus average applies: only the extra order value and the lost fee count). If 200 orders a month top up by an average of £18 at a 45% margin:
That is £3.15 per order, £3,600 revenue and £630 contribution a month. If the customers only add £6 to scrape over the line, the same calculation gives , a loss on every order. Set the threshold a little above the median basket and check what people actually add, not just whether they cross it.
The upsell on the product page. About 600 orders a month are for the medium hamper at £75. The large one costs £110 and the £35 difference carries a 40% margin. If 10% of those buyers move up:
Here , , (only the price difference counts) and . That is £2,100 revenue and £840 contribution, provided the side by side view does not cost conversion, which only a holdout can tell you.
Together the three placements add £6,960 revenue (8.2%) and £2,037 contribution (6.3%) a month from traffic Priya already has. Contribution grows more slowly than revenue, because the threshold gives away delivery fees. That is the honest shape of the result. Anyone promising 40% from a widget is selling the widget.
Rules first, a model only when the order volume justifies it
Sooner or later someone asks about AI recommendations, so here is the plain version of the answer. There are three ways to decide what to show next to a product.
Curated. A person decides that this hamper goes with these three bottles. The quality is high and the coverage is low, and it decays because nobody updates it when the range changes. It suits a range of a few hundred products and someone who cares about the merchandising.
Rules. Companions defined by category and attribute: every hamper shows cards, every vegan hamper shows only vegan extras. Full coverage, decent quality, and it stays right as the range changes because it is derived rather than typed in. This is what I build first, and for many shops it is where I stop.
Order data. "Frequently bought together", computed from real baskets with support, confidence and lift, as in the chapter on market basket analysis. It beats rules once each pair has enough orders behind it that it is not noise. With too few orders, one customer who bought a candle and a dog lead in March becomes a rule that recommends dog leads to candle buyers indefinitely.
A recommendation model sits above all three and needs the order volume of a large shop to beat good rules by a margin you can measure. For a smaller shop I would build the rules, record the events, and revisit once there is enough data to test whether a model earns its keep. How such a model is built inside a store is in the piece on custom AI recommendations in Solidus.
The psychology that holds up in research
A lot of what is written about persuasion in ecommerce comes from people selling the plugin. I have covered pricing psychology and scarcity and loss aversion separately, so here is only what matters for the basket, with the original studies.
Anchoring. Tversky and Kahneman showed in 1974 that people's estimates are pulled towards an initial value, even an arbitrary one.3 On an upsell the first price seen becomes the reference: show the large hamper first and the medium looks reasonable, show the medium first and the large looks expensive. The order matters as much as the discount.
The compromise effect. Simonson showed in 1989 that an option tends to gain share when it becomes the middle option of a set.4 If Priya sells two sizes, many people pick the smaller. Add a larger third and the old large becomes the sensible middle.
The decoy. Huber, Payne and Puto showed in 1982 that adding an option that is clearly worse than one alternative (but not the other) can raise the share of the option that dominates it.5 Use it honestly: the decoy has to be a real product that someone could sensibly buy.
Defaults. Johnson and Goldstein showed with organ donation that the default option has a strong effect on what people end up with.6 That is exactly why pre ticked paid add ons are banned. The legitimate use is to highlight the recommended size, not to put it in the basket.
Thresholds. "You are £9 from free delivery" reframes the extra item as saving the delivery charge. As the worked example shows, it lifts the basket but can cost contribution, which is what Lewis, Singh and Fay found in real data.2
Legibility. An upsell works when the customer can see in a second what the better version gives them. "Serves eight, two bottles, £35 more" tells them. "Premium option" does not.
What is now illegal in the UK
The other half of the persuasion literature is manipulation, and in the UK much of it is no longer a matter of taste. The detailed interface side is in the piece on dark patterns. For the basket:
Pre ticked paid add ons. Under regulation 40 of the Consumer Contracts (Information, Cancellation and Additional Charges) Regulations 2013, any payment beyond the price of the main item needs the customer's express consent before the contract, and consent inferred from a default option, such as a pre ticked box on a website, does not count. If the shop takes the money anyway, it has to pay it back.7
Fake urgency. Since 6 April 2025 the unfair commercial practices rules sit in Part 4 of the Digital Markets, Competition and Consumers Act 2024. Unfair commercial practices are prohibited, misleading actions are one of them,8 and Schedule 20 lists practices that are unfair in all circumstances, including falsely stating that a product or its terms are only available for a limited time to rush a decision.9 A countdown that resets on reload is exactly that. "Only 2 left" when there are two hundred is a misleading action.
Sneaking items into the basket. Supplying products the customer did not request and demanding payment for them is also on the Schedule 20 list.9 A free sample that silently turns into a paid subscription is the classic example.
Consequences. Some breaches of the Act are also criminal offences.10
What about the Digital Services Act? Its Article 25 bans deceptive interface design, but only for providers of online platforms (services that store and publish content for users, such as marketplaces), and it expressly does not apply to practices already covered by the Unfair Commercial Practices Directive or the GDPR.11 For a UK shop selling its own range into the EU, the consumer law of the customer's country is the yardstick, not Article 25.
Interruptions are legal and merely self defeating. A pop up over the checkout offering something else costs attention at the most fragile stage of the shop.1
The pattern is simple. Anything that works by getting the customer to choose something they would not have chosen if they had understood it will eventually cost more than it made. Anything that makes a genuinely good next choice easy to see and easy to take keeps working.
How I build it into Solidus
This is where the platform choice from my comparison of shop systems turns into money. On a rented platform each mechanic tends to be a separate app with its own monthly fee and its own idea of what your product data looks like. In Solidus it is a few models and views in your own code.
Product relationships. A thin table of my own: a relationship type (companion, upgrade, alternative), a source product, a target product or a target rule, and a priority. The rule based part is a scope such as "all extras that share this hamper's dietary attributes". The curated part is a row in the admin. The order data part is a nightly job that computes co purchase counts and writes them to the same table with a lower priority, so a person's judgement always wins over a statistic.
The matching panel. A small view component reads the attributes of the selected variant and asks the relationship scope for companions that match. Switching variants swaps the panel through a Stimulus controller, with no page reload.
Thresholds through the promotion engine. Free delivery above a basket value and a fixed price bundle are promotion rules and actions in Solidus. The basket message asks the same engine how far the order is from qualifying, so the message can never contradict the rule that later applies the discount.
Bundles as one line. For the build your own hamper, the basket variant carries the line item and the customer's picks are stored on it, with a comparison so that two hampers with different contents never merge into one line. Stock for the contents is reduced when the order completes. The customer sees one line at one price, the packing bench sees a pick list, and the margin can be read per component.
The drawer. A Turbo frame that replaces the flash message and shows the added item, the order total, the two highest priority relationships and a threshold message if one applies. Every addition from the drawer is recorded as an event with its source.
Add ons at checkout. One section on the delivery step with genuine delivery options: date, message, next day. Each is a line item or a shipping method, none pre selected, all clearly priced.
It is ordinary application code in a store the client owns: bespoke Solidus code becomes the client's on full payment. When the range changes the rules keep working, a different threshold is a number in the admin, and the events are in your own database.
Measuring lift so you know rather than hope
The people who take an offer are not a random sample. They were already in a buying mood, so comparing orders with a cross sell against orders without one always flatters the offer and says nothing about cause.
The honest method is a holdout: a random share of visitors who never see the placement, and a comparison of revenue per visitor (better, contribution per visitor) between the two groups. The relative lift is a percentage change:
Here is revenue per visitor in the group that sees the placement and is revenue per visitor in the holdout. The method is in the guide to testing methods and the statistics in the piece on significance and error margins.
Sample size. Order values vary a lot, so a lift of 2% or 3% usually needs thousands of orders per group, not hundreds. Work it out before you start with the sample size calculation. At Priya's 1,000 orders a month that means weeks, not days. A test stopped after four days because the dashboard looks good is a coin toss you paid for.
One change at a time. Launch the drawer, the threshold and the upsell in the same week and you will never know which did what. Stagger them or give each its own holdout.
Segment afterwards, not before. Look at the overall lift first, then new against returning customers, mobile against desktop, and by category. A placement that lifts hampers and depresses gift cards can net out to nothing.
Watch the next order. Good cross selling can show up in repeat purchases rather than the first basket, so track revenue per customer over ninety days as well as per session.
In Solidus this is a feature flag on the placement, a cookie that assigns the visitor to a group, and a query. Under the consent rules the assignment cookie is a decision for the shop and its lawyer, and the analysis can run on order data in your own database.
The order I would do it in
First, the numbers. Revenue per visitor, median basket, gross margin per product and the most common product pairs in your order history.
Then rules and the drawer, with a holdout on the drawer.
Then the threshold, just above the median basket, with the delivery cost line watched closely.
Then the product page: matching companions and a three option structure wherever there are sizes or tiers.
Then the after purchase flow, which is slower to show but builds on itself.
I would not install a recommendations app and call it done, put anything in the checkout that is not about delivery, pre tick anything, show a timer, discount a bundle until the added item loses money, or report average order value as the success measure.
And the mechanics should not run ahead of the merchandising. No placement can fix a range where nothing goes with anything. A hamper shop works because a hamper has a card, a bottle and a delivery date that belong with it. If your range has no natural companions, the first job is to add some.
The short version
Put the upsell on the product page, the cross sell in the drawer and the basket, the add ons in one honest section of the checkout, and the next order in the after purchase flow. Watch revenue per visitor and contribution, not average order value. Check that a delivery threshold does not give away more in fees than it adds in margin. Build rules before models, measure with a holdout, and stay on the right side of rules that now have real teeth.
Footnotes
-
Baymard Institute, Cart abandonment rate statistics (average of 50 studies, 70.22%; reasons for abandonment excluding "just browsing", extra costs too high 40%), https://baymard.com/lists/cart-abandonment-rate ↩ ↩2 ↩3
-
Michael Lewis, Vishal Singh and Scott Fay, An empirical study of the impact of nonlinear shipping and handling fees on purchase incidence and expenditure decisions, Marketing Science 25(1), 51 to 64, 2006, https://doi.org/10.1287/mksc.1050.0150 ↩ ↩2
-
Amos Tversky and Daniel Kahneman, Judgment under uncertainty: heuristics and biases, Science 185(4157), 1124 to 1131, 1974, https://doi.org/10.1126/science.185.4157.1124 ↩
-
Itamar Simonson, Choice based on reasons: the case of attraction and compromise effects, Journal of Consumer Research 16(2), 158, 1989, https://doi.org/10.1086/209205 ↩
-
Joel Huber, John W. Payne and Christopher Puto, Adding asymmetrically dominated alternatives: violations of regularity and the similarity hypothesis, Journal of Consumer Research 9(1), 90, 1982, https://doi.org/10.1086/208899 ↩
-
Eric J. Johnson and Daniel Goldstein, Do defaults save lives?, Science 302(5649), 1338 to 1339, 2003, https://doi.org/10.1126/science.1091721 ↩
-
The Consumer Contracts (Information, Cancellation and Additional Charges) Regulations 2013, regulation 40, https://www.legislation.gov.uk/uksi/2013/3134/regulation/40 ↩
-
Digital Markets, Competition and Consumers Act 2024, sections 225 (prohibition of unfair commercial practices) and 226 (misleading actions), https://www.legislation.gov.uk/ukpga/2024/13/section/225 and https://www.legislation.gov.uk/ukpga/2024/13/section/226 ↩
-
Digital Markets, Competition and Consumers Act 2024, Schedule 20, paragraphs 7 and 31, in force 6 April 2025 by S.I. 2025/272, https://www.legislation.gov.uk/ukpga/2024/13/schedule/20 ↩ ↩2
-
Digital Markets, Competition and Consumers Act 2024, section 237 (offences), https://www.legislation.gov.uk/ukpga/2024/13/section/237 ↩
-
Regulation (EU) 2022/2065 (Digital Services Act), Article 25 (online interface design and organisation) and Article 3(i) (definition of online platform), https://eur-lex.europa.eu/eli/reg/2022/2065/oj ↩