--- title: Managing client IDs with server-side rendering slug: oa890580 canonical_url: https://docs.coveo.com/en/oa890580/ collection: build-a-search-ui source_format: adoc --- # Managing client IDs with server-side rendering In [server-side rendering (SSR)](https://web.dev/articles/rendering-on-the-web#server-side), the initial request to Coveo APIs is made from the server rather than the client's browser. This request requires a [client ID](https://docs.coveo.com/en/lbjf0131/) to personalize responses based on the user's behavior and previous interactions. Without effective client ID management, you can't accurately distinguish between new and returning visitors, leading to a lack of personalization and potential issues with session tracking. There are two primary scenarios to consider when managing client IDs in an SSR context: * New visitors: When a user visits the site for the first time, the server generates a unique client ID. The client ID is used to send a request to Coveo, and the response is returned to the browser. This generated client ID is stored in the browser as a cookie, enabling the browser to send it to Coveo for future client-side requests. * Returning visitors: Users who have previously visited the site already have a client ID stored in their browser. When the server receives the request, it retrieves the client ID from the cookie and uses it to send a request to Coveo. While the example in the following section uses Next.js, the same principles apply if you're using a different language or framework in the back-end to perform SSR. > **Note** > > If you're using [Coveo Relay library](https://docs.coveo.com/en/o9je0322/) to send client-side events and a client ID is stored in the browser, Relay will automatically use this stored client ID. ## Code example with Next.js route handlers The following example showcases how to call the search endpoint of the Commerce API server-side and return a pre-rendered HTML file with a list of products. The sample uses Next.js's [route handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) mechanism. > **Note** > > The example given here shows how to make a request to the Commerce API, however, similar logic applies if you're using the Search API. ```ts import { cookies } from "next/headers"; import { search } from "./search"; const COOKIE_NAME = "coveo_visitorId"; <1> interface Product { ec_name: string; ec_description: string; ec_price: number; ec_thumbnails: string[]; } const generateHtmlResponse = (products: Product[]): string => ` SSR

Product List

${ products.length > 0 ? ` ` : `

No products found.

` } `; const getOrCreateClientId = () => { <2> const cookieStore = cookies(); const existingClientId = cookieStore.get(COOKIE_NAME); return existingClientId ? existingClientId.value : crypto.randomUUID(); }; export const GET = async (request: Request) => { const clientId = getOrCreateClientId(); <3> const query = "kayak"; const userAgent = request.headers.get("user-agent") || ""; const locationUrl = request.url; const referrer = request.headers.get("referer") || ""; const searchResults = await search( <4> query, clientId, userAgent, locationUrl, referrer ); const products: Product[] = searchResults.success <5> ? searchResults.data.products || [] : []; const htmlResponse = generateHtmlResponse(products); return new Response(htmlResponse, { <6> status: 200, headers: { "Content-Type": "text/html", "Set-Cookie": `${COOKIE_NAME}=${clientId}; Path=/;`, }, }); }; ``` <1> Define the name of the cookie that stores the Coveo client ID. <2> Create a function that checks if there's an existing client ID present in [`cookies()`](https://nextjs.org/docs/app/api-reference/functions/cookies). If a client ID is found, return it; otherwise, generate and return a new client ID. <3> Get or create a client ID by using the `getOrCreateClientId` function defined earlier. <4> Call the `search` helper function to make a request to the Commerce API. Implementation details for this function are below. <5> Retrieve a list of products returned from the search call. <6> Return the `htmlResponse` generated by the `generateHtmlResponse` helper function. Set the client ID cookie by using the `Set-Cookie` header. The `search` function that makes a request to the Commerce API is as follows: ```ts export async function search( query: string, clientId: string, userAgent: string, locationUrl: string, referrer: string ) { const requestBody = { <1> trackingId: "", clientId, context: { view: { url: locationUrl, }, capture: true, cart: [], user: { userAgent, referrer, }, }, language: "en", country: "US", currency: "USD", page: 0, perPage: 5, facets: [], sort: { sortCriteria: "relevance" }, query, }; const headers = { <2> "Content-Type": "application/json", Authorization: `Bearer ""`, "User-Agent": userAgent, }; try { const response = await fetch("", { <3> method: "POST", headers, body: JSON.stringify(requestBody), }); if (!response.ok) { const errorMessage = await response.text(); return { success: false, status: response.status, message: errorMessage || "Failed to fetch data from Coveo", }; } return { success: true, data: await response.json(), }; } catch (error) { return { success: false, status: 500, message: "Failed to fetch data from Coveo", }; } } ``` <1> Define the request body to send to the Commerce API. Specify the [tracking ID](https://docs.coveo.com/en/n8tg0567/) and other parameters, such as `language` and `currency`. Make sure to forward `context.view.url`, `userAgent`, and `referrer` from the original request to Coveo. <2> Define the headers to send with the request, including a token to [authenticate the request](https://docs.coveo.com/en/n3ge4046/). <3> Make a POST request to the Commerce API with the request body and headers. The URL of the request depends on your organization ID. For more details, see [Organization endpoints](https://docs.coveo.com/en/mcc80216/).