Smart Cart Upsell: Beyond “Customers Also Bought”

Aditya Patni

You're ordering butter chicken and garlic naan. The cart page suggests another butter chicken, from a different restaurant. Or a random chocolate cake that has nothing to do with your North Indian order. Or the platform's highest-margin item, regardless of what you actually want.

That's standard cart upsell in food delivery. Suggestions feel random. Conversion sits in low single digits. Customers learn to ignore the widget entirely.

Where collaborative filtering breaks down

Let me be honest about this: collaborative filtering works. If you're Zomato or DoorDash with millions of orders flowing through, CF learns real item-to-item associations. Given enough signal, it figures out that biryani goes with raita and pizza goes with garlic bread. That's fine.

The failure mode is specific.

New restaurants, new items. A neighborhood biryani place gets 40 orders a day. That's nowhere near enough signal for a collaborative filter to learn meaningful associations. When the restaurant adds a seasonal special, the item is invisible to CF until enough people have ordered it organically. It needs recommendations to get ordered, but needs orders to generate recommendations.

Small platforms without scale. If you're not processing millions of orders, your CF model is working with noise. It can't tell the difference between a genuine pairing and two popular items that happen to show up on the same ticket. Late-night orders all include Coke? Now the model recommends Coke with everything after 10 PM.

Zero food understanding. CF treats every item as an opaque token. It doesn't know that raita cools down a spicy biryani, that naan is eaten with curry, or that two rice dishes in the same meal is redundant. It can't transfer the knowledge that dal goes with rice from Restaurant A to Restaurant B. Every restaurant starts from scratch.

Food-semantic pairing fills this specific gap. Where CF needs thousands of orders to learn that Chicken Tikka Masala pairs with Garlic Naan, a semantic approach recognizes it as a curry-and-bread pairing on sight.

What context-aware pairing looks like

Good upsell understands what's in your cart and what's missing. Biryani cart? Mirchi ka salan is the traditional accompaniment. Burger? Fries and a shake. Ramen? Gyoza. These aren't arbitrary. They're how people eat.

Context-aware suggestion looks at the cart and asks: what cuisine is this? What categories are covered? What's missing? Then it picks items from the restaurant's own menu that fill the gaps.

A cart with Chicken Biryani and Butter Naan: North Indian, non-veg, has a main and a bread. No beverage, no side, no dessert. The engine returns Raita (side), Masala Chai (beverage), Gulab Jamun (dessert). Each fills a gap. Each matches the cuisine.

Compare that to “Customers also bought: Paneer Tikka.” The customer already has a protein-heavy main.

How the suggest endpoint works

The POST /suggest endpoint takes two inputs: the items in the cart and the restaurant's full menu. It returns ranked suggestions with category labels, relevance scores, and human-readable reasons.

import requests

response = requests.post(
    "https://dish-embed.latimal.com/suggest",
    headers={"X-API-Key": "YOUR_KEY", "Content-Type": "application/json"},
    json={
        "cart": ["Butter Chicken", "Garlic Naan"],
        "menu": ["Raita", "Gulab Jamun", "Dal Makhani",
                 "Tandoori Roti", "Mango Lassi", "Chicken Biryani"],
        "top_k": 3
    }
).json()

print(response["suggestions"])

The response includes the detected cuisine, dietary status, which meal categories are covered, and the suggestions themselves:

{
  "suggestions": [
    {"item": "Raita", "category": "side",
     "reason": "No side dish in cart", "score": 0.89},
    {"item": "Mango Lassi", "category": "beverage",
     "reason": "No beverage in cart", "score": 0.85},
    {"item": "Gulab Jamun", "category": "dessert",
     "reason": "No dessert in cart", "score": 0.78}
  ],
  "cart_cuisine": "North Indian",
  "cart_dietary": "non_veg",
  "cart_categories": ["main", "bread"]
}

Notice what didn't get suggested. Chicken Biryani: another heavy main. Dal Makhani: also a main. Tandoori Roti: bread, same category as garlic naan. The engine fills gaps instead of stacking more of what's already there.

What the engine handles

DimensionWhat it does
Cuisine affinityNorth Indian cart gets North Indian sides. Coleslaw won't show up next to dal tadka, even if the restaurant serves both.
Dietary consistencyVegetarian cart never gets non-veg suggestions. Automatic, keyword-based on common proteins. No dietary tags needed in your menu data.
Category diversificationTwo mains in cart? Won't suggest a third. Steers toward missing components: beverage, side, dessert, in priority order.
Cross-restaurant transferKnowledge that dal goes with rice works on every restaurant, including one that onboarded five minutes ago.

Estimating the AOV impact

Back-of-envelope math, for illustration. Assume 10,000 orders per day with an AOV of ₹450.

Generic upsell typically converts at 2-4%. Most users ignore irrelevant suggestions. That's 200-400 add-ons per day, often low-value items.

Best-in-class e-commerce upsell converts at 5-8%. Assume conservatively that context-aware food pairing lands in that range. At 6% conversion on 10,000 orders, with an average add-on of ₹100 (a lassi, a side, a dessert), that's 600 add-ons per day. ₹60,000 in incremental daily revenue, or roughly a 1.3% AOV lift.

Whether the actual lift is 1% or 3% depends on things the pairing engine can't control: suggestion placement, price sensitivity, time of day, and how well your UI sells the recommendation. Which brings up an important caveat.

What this doesn't solve

Food-semantic pairing is maybe 30-40% of a production upsell system. I want to be clear about that.

Price sensitivity. Suggesting a ₹250 dessert on a ₹150 order kills conversion. The API handles food pairing; your business rules need to handle pricing thresholds. A ₹40 raita on a ₹350 order is a different sell than a ₹180 kebab platter on the same order.

Personalization and business rules. Time of day matters. Minimum order thresholds interact with upsell. Some restaurants don't want you pushing their low-margin items. Platform economics have their own constraints. All of this is your logic layer, sitting on top of the pairing signal.

Reliability at checkout. Calling a third-party API synchronously at checkout is a latency and reliability risk. The right pattern: pre-compute suggestions when the menu changes, cache them, and serve from cache at checkout. Use the live API as a fallback for dynamic carts with unusual combinations. Circuit breakers and graceful degradation (fall back to your CF model or a static list) are baseline requirements for anything in the checkout path.

Where and how to show suggestions

Cart page.Highest conversion. The user is reviewing their order and actively thinking about whether it's complete. Show 2-3 suggestions with the reason text (“No beverage in your cart”). One-tap add buttons.

Post-add confirmation. Right after someone adds an item, show a brief toast or bottom sheet: “Goes well with: Mango Lassi.” One suggestion only. The window of attention is small.

Checkout. Last chance before payment. One suggestion with a reason. You want to close the sale, not create decision fatigue.

Always display the reason field from the API. “No beverage in cart” converts better than “You might also like.”

Pairings across cuisines

Indian thali logic. Cart has Dal Tadka and Jeera Rice. Engine suggests Roti (bread missing), Raita (side missing), Gulab Jamun (dessert missing). It won't suggest Paneer Butter Masala because the cart already has a dal-based main.

Pizza meal completion. Cart has a Margherita Pizza. Suggestions: Garlic Bread (side), Coca-Cola (beverage), Tiramisu (dessert). Another pizza won't show up because the main category is covered.

Japanese combos. Cart has Tonkotsu Ramen. Engine suggests Gyoza (side, Japanese cuisine match), Matcha Ice Cream (dessert), Asahi (beverage). Pad Thai won't appear because that's Thai, and the cart is Japanese.

Korean banchan. Cart has Bibimbap. Engine suggests Kimchi (side), Japchae (side, Korean match), Banana Milk (beverage). It won't suggest another rice bowl.

The honest pitch

The rest of a production upsell system, pricing rules, availability checks, time-of-day logic, restaurant-side margin preferences, personalization from purchase history, you probably already have some of that. Or you can build it with straightforward business logic. We're not trying to replace your recommendation stack. We're filling the cold-start and food-knowledge gaps that CF can't cover.

The suggest endpoint is live in the playground. The API reference has the full schema. Try it with your own menu and see if the pairings make sense.