Skip to main content

Upsell & Cross-sell Usage

  • Implementation in file \app\routes\products.$handle.tsx

Configuration

getRecommendations Function

You can customize the behavior of the getRecommendations function by passing next parameters:

  • widgetIds: widgetIds is a list of widget ids that you created on your Fast Simon dashboard. You can pass multiple widget ids to get recommendations from multiple widgets.
  • productId: productId of the product that the results will be based on, this is an optional field for non-personalized based widgets.

For a full documentation about creation widget in Fast Simon, go to Help center - Upsell & Cross-sell widgets.

Return Object

The function returns a Promise of an object type RecommendationsResponse.

FastSimonWidget Component

You can customize the FastSimonWidget component with various props to match your store's design and layout requirements:

  • renderProduct: A function that receives a product object and returns a React element. This allows you to customize the product card for each product in the widget.
  • title: The title of the widget, for example, "Similar Products" or "You may also like".
  • breakpoints: An object of breakpoints to control the number of products displayed on different devices.
  • carouselGap: The gap between products in the carousel (default value: 16px).
  • RightArrowIcon: A JSX element to use as the right arrow icon in the carousel. The left arrow is rotated automatically.
  • imageAspectRatio: The aspect ratio of the product image (default value: "2/3").
<FastSimonWidget
title={'Similar Products'}
products={recommendationsProducts}
renderProduct={(product, pos) => <MyProductCard key={product.id} product={product} />}
breakpoints={{
mobile: 2,
tablet: 3,
desktop: 4
}}
carouselGap={16}
RightArrowIcon={<MyRightArrowIcon />}
imageAspectRatio={"2/3"}/>

Usage Example

Imports

import {CacheLong} from '@shopify/hydrogen';
import {FastSimonWidget , transformToShopifyStructure} from '@fast-simon/storefront-kit';
... // additional imports

Loader Function

export async function loader(args: LoaderFunctionArgs) {
// Start fetching non-critical data without blocking time to first byte
const deferredData = loadDeferredData(args);

// Await the critical data required to render initial state of the page
const criticalData = await loadCriticalData(args);

// Your widgetID from your widgets at Fast Simon dashboard
const widgetIds = ["17301826035377900", "17301826035377911"];

const recommendationsResponse = args.context.fastSimon.getRecommendations({
props: {
widgetIds: widgetIds,
productId: criticalData.product.id
}
});

return defer({...deferredData,
...criticalData,
recommendationsData: recommendationsResponse.then(data => {
return {
uuid: data.uuid,
widget_responses: data.widget_responses.map(widget => {
return {
...widget,
products: transformToShopifyStructure(widget.products)
}
})
}
})
});
}

... // more functions and logic

Display Product

export default function Product() {
const {product, variants, recommendationsData} =
useLoaderData<typeof loader>();
const selectedVariant = useOptimisticVariant(
product.selectedVariant,
variants,
);

const {title, descriptionHtml} = product;

return (
<div className="product">
<ProductImage image={selectedVariant?.image} />
<div className="product-main">
<h1>{title}</h1>
<ProductPrice
price={selectedVariant?.price}
compareAtPrice={selectedVariant?.compareAtPrice}
/>
<br />
<Suspense
fallback={
<ProductForm
product={product}
selectedVariant={selectedVariant}
variants={[]}
/>
}
>
<Await
errorElement="There was a problem loading product variants"
resolve={variants}
>
{(data) => (
<ProductForm
product={product}
selectedVariant={selectedVariant}
variants={data?.product?.variants.nodes || []}
/>
)}
</Await>
</Suspense>
<br />
<br />
<p>
<strong>Description</strong>
</p>
<br />
<div dangerouslySetInnerHTML={{__html: descriptionHtml}} />
<br />
</div>

<Suspense fallback={<div className={'spinner-fallback'}><MyLoadingSpinner/></div> }>
<Await resolve={recommendationsData}>
{(data) => data.widget_responses.map((widget, index) => (
<FastSimonWidget key={index}
title={widget.title}
products={widget.products}
breakpoints={{
mobile: 2,
tablet: 3,
desktop: 4,
}}
RightArrowIcon={<MyRightArrowIcon/>}
imageAspectRatio="3/4"
/>
))}
</Await>
</Suspense>

</div>
);
}