Visual Similarity Usage
- Implementation in file
\app\routes\products.$handle.tsx
Configuration
getVisualSimilarityProducts
Function
You can customize the behavior of the getVisualSimilarityProducts
function by passing the specs
parameter to control aspects such as:
maxSuggestions
: Maximum number of similar products to fetch.sources
: Sources of the results. Example sources:similar_products
: Products sharing category, tags, or keyword similarity with the viewed product.similar_products_by_attributes
: Products sharing categories and chosen attributes (requires selecting relevant attributes in the Fast Simon dashboard).similar_products_lookalike
: Visually similar products (requires enabling Look-alike Visually Similar Recommendations in the Fast Simon dashboard).related_top_products
: Popular products in the store.
For a full list of configurable parameters, refer to the API product recommendation documentation.
Return Object
The function returns a Promise of an object type ServerProduct[]
.
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={visualSimilarityProducts}
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);
const visualSimilarityProducts = await args.context.fastSimon.getVisualSimilarityProducts({
props: {
productId: criticalData.product.id,
},
cacheStrategy: CacheLong(),
});
return defer({...deferredData, ...criticalData, visualSimilarityProducts});
}
... // more functions and logic
Display Product
export default function Product() {
const {product, variants, visualSimilarityProducts} =
useLoaderData<typeof loader>();
const selectedVariant = useOptimisticVariant(
product.selectedVariant,
variants,
);
const fastStructureProducts = transformToShopifyStructure(visualSimilarityProducts);
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>
<FastSimonWidget
title={'Similar Products'}
products={fastStructureProducts}
RightArrowIcon={
<svg
xmlns="http://www.w3.org/2000/svg"
height="1em"
fill="white"
viewBox="0 0 448 512"
>
<path d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z" />
</svg>
}
/>
</div>
);
}