> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tagada.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Cart-value upsell

> Let the order total pick the post-purchase offer — premium upsell for big carts, an easy add-on for small ones, via mainOrder.totalGreaterThan

# Cart-value upsell

**Time**: \~15 minutes | **Difficulty**: Beginner | **Type**: part of [Funnel demos](/developer-tools/funnel-demos/introduction)

<Info>
  **Finished project:** [`cart-value-upsell`](https://github.com/TagadaPay/examples/tree/main/cart-value-upsell). Clone it if you want the working app first — or keep reading and rebuild the same graph.
</Info>

The classic AOV ladder. Orders of **$50 or more** get the premium hoodie upsell — that shopper already showed intent. Smaller orders get a **$9 add-on** instead: an easy yes that still lifts average order value. Unlike the geo and tag demos, nothing is simulated here — the real order total decides.

<img src="https://mintcdn.com/tagadapay/ZVdPq_Zl9I9f0_Ur/assets/images/funnel-demos/cart-value-upsell-graph.png?fit=max&auto=format&n=ZVdPq_Zl9I9f0_Ur&q=85&s=a1bfa10a2d380560398163054c6e0970" alt="Cart-value upsell funnel: checkout, then hoodie for totals of fifty dollars or more, socks otherwise" width="3180" height="706" data-path="assets/images/funnel-demos/cart-value-upsell-graph.png" />

***

## What you need

| Resource          | Role                                  | Example                   |
| ----------------- | ------------------------------------- | ------------------------- |
| Main product      | Cart on landing / checkout (1× or 2×) | Essential Tee · \$29.99   |
| Premium product   | One-click offer, total ≥ \$50         | Heavyweight Hoodie · \$39 |
| Add-on product    | One-click offer, total \< \$50        | Crew Socks · \$9          |
| 2 checkout offers | One per tier                          | `type: 'upsell'`          |

Prices are **integer cents** — the \$50 threshold is `5000`.

***

## The graph

Four steps. The split is two edges out of checkout — the total edge outranks the `always` fallback.

| Step          | `type`     | Path                     | Bound offer |
| ------------- | ---------- | ------------------------ | ----------- |
| Landing       | `landing`  | `/`                      | —           |
| Checkout      | `checkout` | `/checkout`              | —           |
| Premium offer | `offer`    | `/offer-hoodie/:orderId` | Hoodie \$39 |
| Add-on offer  | `offer`    | `/offer-socks/:orderId`  | Socks \$9   |
| Thank you     | `thankyou` | `/thankyou/:orderId`     | —           |

| Edge                     | `when`                                          | `priority` |
| ------------------------ | ----------------------------------------------- | ---------- |
| Checkout → Premium offer | `mainOrder.totalGreaterThan` `{ amount: 5000 }` | 10         |
| Checkout → Add-on offer  | `always`                                        | 1          |
| Each offer → Thank you   | (none — accept or decline)                      | —          |

```ts theme={null}
edges: [
  { id: 'e_land', source: 'step_landing', target: 'step_checkout' },
  {
    id: 'e_premium',
    source: 'step_checkout',
    target: 'step_offer_hoodie',
    conditions: { when: { 'mainOrder.totalGreaterThan': { amount: 5000 } }, priority: 10 },
  },
  {
    id: 'e_addon',
    source: 'step_checkout',
    target: 'step_offer_socks',
    conditions: { when: 'always', priority: 1 },
  },
  { id: 'e_premium_done', source: 'step_offer_hoodie', target: 'step_thankyou' },
  { id: 'e_addon_done', source: 'step_offer_socks', target: 'step_thankyou' },
]
```

<Note>
  Related conditions: `mainOrder.hasProduct` `{ productId }` routes on *what* they bought instead of how much; `lastOrder.totalGreaterThan` looks at the most recent order in the session (useful after an accepted offer); `payment.amountGreaterThan` checks the payment itself.
</Note>

***

## Same type on the Headless SDK

Self-hosted, load the main order on the offer route and branch on its amount. The [finished project](https://github.com/TagadaPay/examples/tree/main/cart-value-upsell) keeps `/offer` as **one route**:

```tsx theme={null}
// /offer — one route, two possible offers, real signal
export function ValueOffer() {
  const [params] = useSearchParams();
  const orderId = params.get('orderId');
  const { order, isLoading } = useOrder(orderId);

  if (isLoading || !order) return <p>Checking your order total…</p>;

  if (order.amount >= 5000) {
    return (
      <Offer
        offerId={HOODIE_OFFER_ID}
        title="Heavyweight Hoodie — big-cart exclusive"
        priceLabel="$39.00"
        acceptPath="/thank-you"
        declinePath="/thank-you"
      />
    );
  }
  return (
    <Offer
      offerId={SOCKS_OFFER_ID}
      title="Crew Socks — easy add-on"
      priceLabel="$9.00"
      acceptPath="/thank-you"
      declinePath="/thank-you"
    />
  );
}
```

Accepting still charges the saved card in one click via `processOfferPayment({ offerId, mainOrderId })`.

<Tip>
  The demo landing sells **1 tee ($29.99) or 2 tees ($59.98)** so both tiers are one click apart. Buy 1, see the socks. Buy 2, see the hoodie.
</Tip>

***

## Paths the customer can take

| Cart   | Total   | Offer shown             | If accepted   |
| ------ | ------- | ----------------------- | ------------- |
| 1 tee  | \$29.99 | Crew Socks \$9          | Tee + socks   |
| 2 tees | \$59.98 | Heavyweight Hoodie \$39 | Tees + hoodie |

Every accepted offer appears on thank you as a **related order** (`relatedOrders[]`), exactly like the [basic post-purchase](/developer-tools/funnel-demos/basic-post-purchase#thank-you-related-orders) demo.

***

## Next

<CardGroup cols={2}>
  <Card title="Finished project on GitHub" icon="github" href="https://github.com/TagadaPay/examples/tree/main/cart-value-upsell">
    Clone `cart-value-upsell` and try both cart sizes in a minute
  </Card>

  <Card title="Basic post-purchase" icon="shirt" href="/developer-tools/funnel-demos/basic-post-purchase">
    Start here if this is your first funnel demo
  </Card>

  <Card title="Geo-based offers" icon="earth-americas" href="/developer-tools/funnel-demos/geo-offers">
    Same split, driven by the visitor's country
  </Card>

  <Card title="Funnel Orchestrator" icon="diagram-project" href="/developer-tools/funnels/funnel-orchestrator">
    Nodes, edges, conditions, priorities
  </Card>
</CardGroup>
