---
title: Build recommendation interfaces (SSR)
slug: p25b0248
canonical_url: https://docs.coveo.com/en/p25b0248/
collection: coveo-for-commerce
source_format: adoc
---
# Build recommendation interfaces (SSR)
> **Important**
>
> The Headless Commerce SSR utilities are in open beta.
> Contact your Coveo representative for support in adopting this.
To implement a [server-side rendering (SSR)](https://docs.coveo.com/en/p2af0263/) commerce recommendations interface, use the [Headless](https://docs.coveo.com/en/lcdf0493/) [`Recommendations`](https://docs.coveo.com/en/headless-react/latest/reference/interfaces/SSR_Commerce.index.Recommendations.html) controller hooks and a recommendation [provider](https://docs.coveo.com/en/obif0156#create-providers).
## Prerequisites
Before you begin building your recommendation interfaces, make sure you:
. [Understand how recommendation interfaces work](https://docs.coveo.com/en/o4ue0204/).
. [Create recommendation configurations](https://docs.coveo.com/en/o8880463/).
## Define and retrieve the target recommendation controller hooks
When [defining your commerce engine](https://docs.coveo.com/en/obif0156#define-the-commerce-engine-and-controllers), leverage the [`defineRecommendations`](https://docs.coveo.com/en/headless-react/latest/reference/functions/SSR_Commerce.index.defineRecommendations.html) functions to define and retrieve the target recommendation hooks.
```tsx
// lib/commerce-engine-config.ts
import {
defineRecommendations,
// ...
} from '@coveo/headless-react/ssr-commerce';
export default {
// ...
controllers: {
popularViewed: defineRecommendations({ <1>
options: {
slotId: 'd73afbd2-8521-4ee6-a9b8-31f064721e73',
},
}),
popularBought: defineRecommendations({
options: {
slotId: 'af4fb7ba-6641-4b67-9cf9-be67e9f30174',
},
}),
viewedTogether: defineRecommendations({
options: {
slotId: 'ff5d8804-d398-4dd5-b68c-6a729c66454b',
},
}),
// ...
},
} satisfies CommerceEngineDefinitionOptions;
```
<1> For each target recommendation controller hook, specify the `slotId` of the recommendation slot configuration.
The `slotId` is the unique identifier of the slot you want to retrieve recommendations for.
This corresponds to the `id` field of the [recommendation slot configuration](https://docs.coveo.com/en/o8880463/) you've created.
## Create recommendation components
Next, create recommendation components that use the target recommendation controller hooks.
The following is an example implementation for the `popularBought` strategy.
```tsx
// components/recommendations/popular-bought.tsx
'use client';
import {usePopularBought} from '@/lib/commerce-engine';
import ProductButtonWithImage from '../product-button-with-image';
export default function PopularBought() {
const {state, methods} = usePopularBought();
return (
<>
{state.headline}
{state.products.map((product) => ( <1>
-
<2>
))}
>
);
}
```
<1> Display each recommended product.
<2> Use a product button component that uses the [`interactiveProduct`](https://docs.coveo.com/en/headless-react/latest/reference/interfaces/SSR_Commerce.index.InteractiveProduct.html) function to correctly log the product click and also handle navigation.
See [Displaying products](https://docs.coveo.com/en/oc685393#display-the-target-product).
The recommendation components can then be included in the target pages.
## Display recommendations with your recommendation provider
When displaying your recommendation components in a page, wrap them in your recommendation provider.
The following is an example of a cart page with a `popularBought` recommendation component, simplified to focus on the recommendation part.
```tsx
// app/cart/page.tsx
// runs server-side
// ...
import {
RecommendationProvider,
// ...
} from '@/components/providers/providers';
import PopularBought from '@/components/recommendations/popular-bought';
import {
recommendationEngineDefinition,
// ...
} from '@/lib/commerce-engine';
import {NextJsNavigatorContext} from '@/lib/navigatorContextProvider';
import {defaultContext} from '@/utils/context';
import {headers} from 'next/headers';
export default async function Search() {
const navigatorContext = new NextJsNavigatorContext(headers()); <1>
standaloneEngineDefinition.setNavigatorContextProvider(
() => navigatorContext
);
const items = // ... <2>
const recsStaticState = await recommendationEngineDefinition.fetchStaticState(
{
controllers: {
popularBought: {enabled: true}, <3>
popularViewed: {enabled: false},
viewedTogether: {enabled: false},
cart: {initialState: [items](https://docs.coveo.com/en/210/)},
context: {
language: defaultContext.language,
country: defaultContext.country,
currency: defaultContext.currency,
view: {
url: 'https://sports.barca.group/cart',
},
},
},
}
);
return (
// ...
staticState={recsStaticState}
navigatorContext={navigatorContext.marshal}
>
// ...
);
}
export const dynamic = 'force-dynamic';
```
<1> [Create a navigation context provider](https://docs.coveo.com/en/obif0156#create-a-navigation-context-provider).
<2> Retrieve [cart items](https://docs.coveo.com/en/oc685394/).
<3> Setting `popularBought.enabled` to `true` lets Headless fetch and refresh `popularBought` recommendations.
In the following line, you set `popularViewed.enabled` to `false` because you don't need to fetch and refresh `popularViewed` recommendations in this component.
And again in the following, you set `viewedTogether.enabled` to `false` because you don't need to fetch and refresh `viewedTogether` recommendations in this component.
<4> Wrap your recommendations components with your recommendation [provider](https://docs.coveo.com/en/obif0156#create-providers).
This code sample was abbreviated to focus on recommendations.
For the full sample, see the [Headless repository](https://github.com/coveo/ui-kit/tree/main/samples/headless-ssr/commerce-nextjs/app/cart/page.tsx).