Cross-Sell and Upsell Functionality

OrderItems can include upsell and crossSell arrays containing related offers that can be displayed to customers during checkout.

Understanding Upsells vs Cross-Sells

  • Upsells (upsell): Higher-tier versions of the current offer (e.g., upgrading from Basic to Premium)

  • Cross-Sells (crossSell): Complementary products that enhance the primary purchase (e.g., adding antivirus software when buying a VPN)

Cascade Removal for Cross-Sells

Cross-sell items can be configured with cross_sell_cascade_removal__limio: true in the offer attributes. When enabled, removing the parent offer will automatically remove all associated cross-sell items.

Example:

import React from "react"
import { useBasket } from "@limio/sdk"

const BasketWithCrossSells = () => {
  const { orderItems, removeFromBasket } = useBasket()

  return (
    <div>
      {orderItems.map(item => (
        <div key={item.id}>
          <h3>{item.name}</h3>

          {/* Display upsell opportunities */}
          {item.upsell && item.upsell.length > 0 && (
            <div className="upsell-section">
              <h4>Upgrade Options:</h4>
              {item.upsell.map(upsellOffer => (
                <div key={upsellOffer.path}>
                  <span>{upsellOffer.data.attributes.display_name__limio}</span>
                  {/* Add functionality to swap to upsell */}
                </div>
              ))}
            </div>
          )}

          {/* Display cross-sell opportunities */}
          {item.crossSell && item.crossSell.length > 0 && (
            <div className="crosssell-section">
              <h4>You Might Also Like:</h4>
              {item.crossSell.map(crossSellOffer => (
                <div key={crossSellOffer.path}>
                  <span>{crossSellOffer.data.attributes.display_name__limio}</span>
                  {/* Add functionality to add cross-sell to basket */}
                </div>
              ))}
            </div>
          )}

          <button onClick={() => removeFromBasket(item)}>
            Remove
            {item.crossSell?.some(cs =>
              cs.data.attributes.cross_sell_cascade_removal__limio
            ) && " (will also remove linked items)"}
          </button>
        </div>
      ))}
    </div>
  )
}

Implementation Example: Complete Upsell/Cross-Sell Flow

import React, { useState } from "react"
import { useBasket } from "@limio/sdk"

const CheckoutWithRecommendations = () => {
  const { orderItems, addToBasket, swapOffer, removeFromBasket } = useBasket()
  const [expandedItem, setExpandedItem] = useState(null)

  const handleUpsell = async (itemId, upsellOffer) => {
    await swapOffer(itemId, upsellOffer)
  }

  const handleCrossSell = async (crossSellOffer) => {
    await addToBasket(crossSellOffer, { quantity: 1, sync: true })
  }

  return (
    <div className="checkout-cart">
      <h2>Your Cart</h2>

      {orderItems.map(item => (
        <div key={item.id} className="cart-item">
          <div className="item-header">
            <h3>{item.name}</h3>
            <span className="price">
              {item.price.currency} {item.price.amount}
            </span>
          </div>

          {/* Show upsell options */}
          {item.upsell?.length > 0 && (
            <div className="upsell-banner">
              <h4>🚀 Upgrade Available!</h4>
              {item.upsell.map(upsell => (
                <div key={upsell.path} className="upsell-option">
                  <span>{upsell.data.attributes.display_name__limio}</span>
                  <button onClick={() => handleUpsell(item.id, upsell)}>
                    Upgrade Now
                  </button>
                </div>
              ))}
            </div>
          )}

          {/* Show cross-sell options */}
          {item.crossSell?.length > 0 && (
            <div className="crosssell-section">
              <button
                onClick={() => setExpandedItem(
                  expandedItem === item.id ? null : item.id
                )}
              >
                {expandedItem === item.id ? "Hide" : "Show"} Related Products
              </button>

              {expandedItem === item.id && (
                <div className="crosssell-grid">
                  {item.crossSell.map(crossSell => (
                    <div key={crossSell.path} className="crosssell-card">
                      <h5>
                        {crossSell.data.attributes.display_name__limio}
                      </h5>
                      <button onClick={() => handleCrossSell(crossSell)}>
                        Add to Cart
                      </button>
                    </div>
                  ))}
                </div>
              )}
            </div>
          )}

          <button onClick={() => removeFromBasket(item)}>
            Remove from Cart
          </button>
        </div>
      ))}
    </div>
  )
}

export default CheckoutWithRecommendations

Last updated

Was this helpful?