# Using version 2 of the Frontend SDK Learn about using various features of version 2 of the Frontend SDK. The Frontend SDK, its integrations, components, and dependencies are ready to use out-of-the-box and should not require further installation. To check if the SDK is successfully installed for your project, or to manually install it, see [Installing the Frontend SDK](/frontend-development/installing-the-frontend-sdk.md). ## Configure the SDK The `configure` method is defined on the [base SDK main class](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/library/SDK.ts) in the `@commercetools/frontend-sdk` library and has several optional and required properties, the required properties will already be set up in your project using the `defaultConfigure` method in the `CommercetoolsSDK.ts` template file. The `configure` method supports the following options: - `locale` - String - Required. The combination of the language and country code in ISO 639-1 and ISO 3166-1 format respectively. For example, `en-DE` or `en_DE`. In your code, you can access the `locale` from the `PageProps.params.locale` (Next.js 12) or using the `useParams()` hook (Next.js 13). - `currency` - String - Required. The three-letter [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) Currency Code. For example, `EUR`. For more information, see [supported currencies](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/Currency.ts). - `endpoint` - String - Required. The full URL of the API hub endpoint. - `extensionVersion` - String - Required. The extension bundle version to connect to. - `useCurrencyInLocale` - Boolean - Optional. If `true`, the currency is required in the `locale` in the format `LOCALE@CURRENCY`. Defaults to `false`. Overrides the `currency` option. - `sessionLifetime` - Number - Optional. This is the amount of time in milliseconds for which a user's session persists before needing to log in again. Overrides the [default session lifetime](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/constants/defaultSessionLifetime.ts) of three months. - `customHeaderValue` - String - Optional. This is the value sent as the `coFE-Custom-Configuration` header value with every request. You can override this value on a specific request by setting the `customHeaderValue` option in the [API methods](/frontend-development/using-the-frontend-sdk.md#api-methods). To access this value globally, call the `SDK.customHeaderValue()` function. - `cookieHandlingOverride` - [CookieManager](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/cookieHandling/CookieManager.ts) - Optional. This option gives the user the ability to extend or override the default base SDK's [CookieHandler](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/library/CookieHandler.ts). The following code example shows how to extend the default cookie handling using the `defaultConfigure` method in the [SDK template file](/frontend-development/frontend-sdk.md#sdk-template-file). ```ts title="Example code to specify custom cookie handling logic" import { sdk } from 'src/sdk'; import { CookieHandler, ServerOptions } from '@commercetools/frontend-sdk'; const cookieHandler = new CookieHandler(); sdk.configure({ ... cookieHandlingOverride: { setCookie: async (key: string, data: any, options?: ServerOptions) => { cookieHandler.setCookie(key, data, options); }, getCookie: async (key: string, options?: ServerOptions) => { return cookieHandler.getCookie(key, options); }, getCookies: async (options?: ServerOptions) => { return cookieHandler.getCookies(options); }, deleteCookie: async (key: string, options?: ServerOptions) => { return cookieHandler.deleteCookie(key, options); }, hasCookie: async (key: string, options?: ServerOptions) => { return cookieHandler.hasCookie(key, options); }, }, }); ``` - `redactionHandlingOverride` - [RedactionManager](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/redactionHandling/RedactionManager.ts) and [RedactionManagerConfig](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/redactionHandling/RedactionManagerConfig.ts) - Optional. This option lets the user override the default redaction behavior of the base SDK's events, such as redacting passwords from event properties and URL parameters. You can extend or override the default functionality by passing a class or object that implements the [RedactionManager](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/redactionHandling/RedactionManager.ts) interface. You can override the [default redaction rules](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/constants/defaultRedactionRules.ts) by passing a [RedactionManagerConfig](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/redactionHandling/RedactionManagerConfig.ts) object. The following code example shows how to extend or override the default redaction handling methods using the `defaultConfigure` method in the [SDK template file](/frontend-development/frontend-sdk.md#sdk-template-file). ```ts title="Example of custom redaction handling logic" import { sdk } from 'src/sdk'; import { RedactionHandler, ServerOptions } from '@commercetools/frontend-sdk'; const redactionHandler = new RedactionHandler(); sdk.configure({ ... redactionHandlingOverride: { redact: async (data: T) => { return redactionHandler.redact(data); }, redactUrl: async (url: string) => { return redactionHandler.redactUrl(data); } }, }); ``` The following code example shows how to override the default redaction handling configuration using the `defaultConfigure` method in the [SDK template file](/frontend-development/frontend-sdk.md#sdk-template-file). ```ts title="Example code to specify custom redaction handling configuration" import { sdk } from 'src/sdk'; import { RedactionManagerConfig, ServerOptions } from '@commercetools/frontend-sdk'; const customRedactConfig: RedactionManagerConfig = { paths: [{ value: "my.path.toRedact", caseSensitive: true }], properties: [], whitelistPaths: [{ "my.non_sensitive.password", caseSensitive: true }], includes: [{ value: "password" }, { value: "token" }], jsonRedactionText: "", urlRedactionText: "CUSTOM_URL_REDACT_TEXT", } sdk.configure({ ... redactionHandlingOverride: customRedactConfig, }); ``` ## Manage the action queue The SDK provides a centralized queue to manage asynchronous operations. You can use the following method and properties to monitor and control the state of pending actions. This feature is available in SDK version 2.1.0 and later. ### Queue method The SDK exposes the following method to manage the internal action queue: #### flush() Use the `flush()` method to wait for all pending actions in the queue to be completed. This is useful for preventing data loss before page navigation or other critical operations. ```ts // Wait indefinitely for all pending actions await sdk.queue.flush(); // Wait with a 5-second timeout await sdk.queue.flush(5000); ``` ### Queue properties | Property | Type | Description | | :--- | :--- | :--- | | `length` | `number` | Total number of actions currently waiting in the queue. | | `isPending` | `boolean` | Returns `true` if an action is currently being processed by the SDK. | ```ts // Check queue status if (sdk.queue.length > 0 || sdk.queue.isPending) { console.log('Actions are still pending'); } ``` ## API methods The base SDK provides various methods to interact with the backend extensions API. We recommend using the SDK methods for all backend extension requests because the base SDK lets you [configure](/frontend-development/using-the-frontend-sdk.md#configure-the-sdk) options such as the locale, currency, endpoint, and extension version, and it maintains these and the user session throughout your application. All API methods return the [SDKResponse](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/sdk/SDKResponse.ts) type, which has an `isError` boolean property that you can use for [narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html). When `isError` is `false`, the response contains a `data` property with the return type from the API hub. When `true`, the response contains an `error` property that includes the error details. In both responses, the `SDKResponse` also contains tracing information for use in debugging and logging. All request methods mentioned in the following sections are `POST` methods. ### callAction The `callAction` method lets you make requests to the action extensions. The method takes the expected return type as its generic argument that defines the type of `data` returned in the [SDKResponse](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/sdk/SDKResponse.ts) of a successful request. It also accepts the following options: - `actionName` - String - Required. The name of the action extension to call. For example, use `product/getProduct` to call the following extension: `{ actions: { product: { getProduct: (...) => { ... } } } }`. - `payload` - [AcceptedPayloadTypes](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/Payload.ts) - Optional. A payload object with key-value pairs to be serialized into the request body. - `query` - [AcceptedQueryTypes](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/Query.ts) - Optional. An object of key-value pairs to be serialized into the request query parameters. - `parallel` - Boolean - Optional. Defaults to `true`. If set to `true`, the action is executed asynchronously. If set to `false`, the action is added to a queue and executed in sequence. Setting to false is useful for actions that may cause race conditions. - `customHeaderValue` - String - Optional. The value to assign to the `coFE-Custom-Configuration` header value. Overrides the global `customHeaderValue` option set when [configuring](/frontend-development/using-the-frontend-sdk.md#configure-the-sdk) the SDK. - `serverOptions` - [ServerOptions](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/cookieHandling/ServerOptions.ts) - Optional for client-side configuration and required for server-side session management. Contains the `req` object of type [IncomingMessage](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpincomingmessage) and `res` object of type [ServerResponse](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpserverresponse) with cookies. The following code example uses the `callAction` method to call a custom extension `customActions/getCustomerCoupons` with a custom header, query, and payload to be executed in sequence. You only need to use the `callAction` method for custom actions. For commercetools extensions, you can use the `sdk.composableCommerce` integration to access the extensions which internally use `callAction` and already have the types and parameters completed. ```ts title="Example of the callAction method to get customer's coupon information" const response = await sdk.callAction({ actionName: 'customActions/getCustomerCoupons', payload: { customer: { email: 'username@example.com' } }, query: { customerId: '4' }, parallel: false, customHeaderValue: '{"customerAuthId":9188377992}', }); if (response.isError) { setError(response.error); } else { setCustomer(response.data); } ``` ### getPage The `getPage` method retrieves the page or redirect data for static and dynamic pages from the API hub. This method is primarily used to fetch the page data from the Studio and render the pages with the Frontend components. This method is used at the catch-all route [`packages//frontend/app/[locale]/[[...slug]]/page.tsx`](https://github.com/FrontasticGmbH/scaffold-b2c/blob/main/frontend/app/%5Blocale%5D/%5B%5B...slug%5D%5D/page.tsx). This method accepts the following options: - `path` - String - Required. The relative path of the page of which you want to fetch the data. For example, `/sale` or `/home/best-sellers`. - `query` - Object - Optional. An object of key-value pairs to be serialized into the URL query parameters. It accepts the value types specified in [AcceptedQueryTypes](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/Query.ts). - `customHeaderValue` - String - Optional. The value to assign to the `coFE-Custom-Configuration` header value. Overrides the global `customHeaderValue` option set when [configuring](/frontend-development/using-the-frontend-sdk.md#configure-the-sdk) the SDK. - `serverOptions` - [ServerOptions](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/cookieHandling/ServerOptions.ts) - Optional for client-side configuration and required for server-side session management. Contains the `req` object of type [IncomingMessage](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpincomingmessage) and `res` object of type [ServerResponse](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpserverresponse) with cookies. The following code example uses the `getPage` method to get the `/sale` page information with a query and custom header: ```ts title="Example of the getPage method to get page data" const response = await sdk.page.getPage({ path: '/sale', query: { size: 'M' }, customHeaderValue: '{"customerAuthId":9188377992}', }); if (response.isError) { const router = useRouter(); router.push('/404'); } else { setPageData(response.data); } ``` ### getPreview The `getPreview` method retrieves the preview data for Studio page previews, used at [`packages//frontend/app/[locale]/preview/[previewId]/page.tsx`](https://github.com/FrontasticGmbH/scaffold-b2c/blob/main/frontend/app/%5Blocale%5D/preview/%5BpreviewId%5D/page.tsx). This method accepts the following options: - `previewId` - String - Required. A string representing the ID of the preview to fetch. - `customHeaderValue` - String - Optional. The value to assign to the `coFE-Custom-Configuration` header value. Overrides the global `customHeaderValue` option set when [configuring](/frontend-development/using-the-frontend-sdk.md#configure-the-sdk) the SDK. - `serverOptions` - [ServerOptions](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/cookieHandling/ServerOptions.ts) - Optional for client-side configuration and required for server-side session management. Contains the `req` object of type [IncomingMessage](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpincomingmessage) and `res` object of type [ServerResponse](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpserverresponse) with cookies. The following code example uses the `getPreview` method to get page preview data with the `previewId` and custom header: ```ts title="Example of the getPreview method to get page preview data" const response = await sdk.page.getPreview({ previewId: 'p9986b2d', // Replace this with the variable containing the previewId customHeaderValue: '{"customerAuthId":9188377992}', }); if (response.isError) { handleError(response.error); } else { setPreviewData(response.data); } ``` ### getPages The `getPages` method lets you fetch the page data for a page folder and all its sub-pages. This method is primarily used in B2C projects to generate the sitemap for static pages at [`packages//frontend/app/[locale]/sitemap-static.xml/route.ts`](https://github.com/FrontasticGmbH/components/tree/1.17.0/app/%5Blocale%5D/sitemap-static.xml/route.ts). This method accepts the following options: - `path` - String - Optional. Defaults to `/`. The relative path of the page of which you want to fetch the data. - `depth` - Number - Optional. Defaults to `16`. The depth of the page folder tree up to which you want to fetch the data. - `types` - String - Optional. Defaults to `static`. The types of pages to fetch. - `customHeaderValue` - String - Optional. Defaults to an empty string. The value to assign to the `coFE-Custom-Configuration` header value. Overrides the global `customHeaderValue` option set when [configuring](/frontend-development/using-the-frontend-sdk.md#configure-the-sdk) the SDK. - `serverOptions` - [ServerOptions](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/types/cookieHandling/ServerOptions.ts) - Optional for client-side configuration and required for server-side session management. Contains the `req` object of type [IncomingMessage](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpincomingmessage) and `res` object of type [ServerResponse](https://nodejs.org/docs/latest-v18.x/api/http.html#class-httpserverresponse) with cookies. The following code example uses the `getPages` method to get the page data for all pages under the `/sale` hierarchy up to two levels deep. For example, `/sale`, `/sale/shirts`, `/sale/shirts/special`, and so on. ```ts title="Example of the getPages method to get page data for multiple pages" const response = await sdk.page.getPages({ path: '/sale', depth: 2, customHeaderValue: '{"customerAuthId":9188377992}', }); if (response.isError) { handleError(response.error); } else { generateSitemap(response.data.pageFolderStructure); } ``` ## Add SDK integrations It is possible to extend the SDK with the [integrations you develop](/frontend-development/developing-sdk-integrations.md). To do so, set up the integrations in the `CommercetoolsSDK` constructor and pass the SDK instance, such as the `ComposableCommerce` instance. For example: ```ts title="Initialize an integration in the SDK" //.... Other code constructor() { super(); // customIntegration is an example name here this.customIntegration = new CustomIntegration(this); } //.... Other code ``` Additionally, any custom events must be added to the SDK generic type as a type intersection. For example: ```ts title="Add custom integration events type using intersection" class CommercetoolsSDK extends SDK { ... } ``` The backend actions must be added to your backend service to extend your extensions API. ## The event engine The commercetools Frontend SDK comes with event management tools to let integrations communicate with other integrations and the user of the integration to add or create an event handler. The source for this functionality is the [`EventManager`](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/library/EventManager.ts) class, extended by the SDK. It is also possible to extend the event types with custom events with the generic argument passed from the SDK. Following is a description of the three methods available on the SDK to manage event handlers: - `trigger` is called to trigger an event, for which an instance of the [`Event`](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/library/Event.ts) class from `@comercetools/frontend-sdk` is passed. An event is constructed with `eventName` and `data`. The `eventName` corresponds to the `[key: string]` value in `@comercetools/frontend-sdk`'s `StandardEvents`. In custom events `data` corresponds to the type of value set for the event. For example, to trigger the `marketingBannerClicked` custom event, `trigger` is called on the `sdk` and an event constructed with `eventName: 'marketingBannerClicked'` and `data: { id: "" }` is passed. - `on` is called to add an event handler for an event. The method takes the `eventName` and `handler` arguments. For example, for the `marketingBannerClicked` custom event, `marketingBannerClicked` is passed for the `eventName` argument and a function with `event` parameter of type `{ data: { id: "" } }` is passed for the `handler` argument. - `off` is called to remove an event handler. For example, to persist the handler only for the lifecycle of a particular component. The function takes the same arguments as the `on` function. For it to work, a named function for the `handler` argument must be defined. To successfully pass a named function to the `handler` parameter, the `event` type in the function's argument must be fully typed, as shown in the following examples. Events are likely to be triggered only during action calls. The integrations you use may also create handlers so they can communicate with other integrations. However, you must be careful to avoid infinite recursion by mistakenly triggering events from event handlers. The SDK event engine should only be used for events specific to the base SDK and integrations. The standard [React events](https://react.dev/learn/responding-to-events) should be used for component events such as `onclick` and `onchange`. ### Create custom events handlers The commercetools Frontend SDK lets you create custom events that you can trigger from within the application, such as when clicking on a particular component or holding the pointer over it. By default, event triggers and handlers will exist for the website's lifetime. However, you may want some to exist only during the lifetime of a specific React component. In that case, you must remove the event handlers on component unmounts. Otherwise, events can stack up due to component unmounting and remounting and may attempt to perform state updates on unmounted components, depending on the nature of the custom events. To understand event handlers better, let's suppose you have a `MarketingBanner` component and you want to track how many times the banner image is clicked using the `marketingBannerClicked` event. To achieve this behavior, the `MarketingBanner` component can use the `onClick` React event handler, which triggers the `marketingBannerClicked` event. To add custom event triggers to the SDK event definition, follow these steps: 1. Create a `MyCustomEvents.ts` file in the `packages/PROJECT_NAME/frontend/sdk` folder with the following content: ```ts title="Custom events type definition" // packages/PROJECT_NAME/frontend/sdk/MyCustomEvents.ts export type MyCustomEvents = { marketingBannerClicked: { id: string }; }; ``` 2. Add the type you created to the `CommercetoolsSDK` class in the generic SDK argument. The type must be added in the form of an intersection, as shown in the following example: ```ts title="Extend the base SDK type with custom events type" // packages/PROJECT_NAME/frontend/sdk/CommercetoolsSDK.ts import { SDK } from "@commercetools/frontend-sdk"; import { ComposableCommerce, ComposableCommerceEvents } from "@commercetools/frontend-composable-commerce"; import { MyCustomEvents } from "./MyCustomEvents"; class CommercetoolsSDK extends SDK { ... } ... ``` 3. Implement the `MarketingBanner` React component. In this example, we're making a simple banner component with an image. ```tsx title="MarketingBanner React component implementation with event handlers" import Image from 'next/image'; import { useEffect } from 'react'; import { sdk } from '../../sdk'; import { Event } from '@commercetools/frontend-sdk'; interface Props { marketingId: string; imageSrc: string; } const MarketingBanner = ({ marketingId, imageSrc }: Props) => { const marketingBannerClickedHandler = ( event: Event< 'marketingBannerClicked', { id: string; } > ) => { // Perform custom event handling logic here. console.log('Marketing banner clicked, id: ' + event.data.id); }; const clickHandler = (id: string) => { sdk.trigger( new Event({ eventName: 'marketingBannerClicked', data: { id: id, }, }) ); }; useEffect(() => { sdk.on('marketingBannerClicked', marketingBannerClickedHandler); return () => { sdk.off('marketingBannerClicked', marketingBannerClickedHandler); }; }, []); return clickHandler(marketingId)} />; }; export default MarketingBanner; ``` We define a function named `marketingBannerClickedHandler` that takes a parameter `event` of class [`Event`](https://github.com/FrontasticGmbH/frontend-sdk/blob/master/src/library/Event.ts) from the `@commercetools/frontend-sdk` library. This class takes the `EventName` and `EventData` parameters as the generic arguments, matching the event we defined earlier in the `MyCustomEvents.ts` file by name (key) and data (value) respectively. Then, we define a function `clickHandler` that constructs the `marketingBannerClicked` event and triggers it using the `sdk.trigger` method. The event has the following properties: - `eventName`: the name of the custom event. - `data`: value of the custom event where `id` is the identifier of the clicked marketing banner. Then, we use the React [`useEffect`](https://react.dev/reference/react/useEffect) hook to call `sdk.on` to set up the event handler on component mount and `sdk.off` to remove the handler on component unmount by passing the named handler on both occasions. Finally we call the `clickHandler` from the `onClick` event of the `Image` component. For more information about how you can extend the SDK with integrations, see [Developing SDK integrations](/frontend-development/developing-sdk-integrations.md). ### Manage sessions The SDK provides built-in tools to handle the user lifecycle, ensuring that authentication states are synchronized between the client and the server. Session management is essential for security because it ensures that sensitive cookies are purged and background processes are correctly halted during logout. #### invalidateSession() The `invalidateSession()` method is the primary tool to perform a session cleanup during logout. It orchestrates a multi-step cleanup process to prevent "zombie sessions." In such sessions, a user appears logged out in the UI, but stale authentication cookies remain active in the browser. This method is available in SDK version 2.1.0 and later. You must always call `invalidateSession()` as the final step of your logout logic. This ensures that even if a background request was slow, it finishes before the user's credentials are removed. ##### Method Signature ```ts title="invalidateSession() method signature" sdk.invalidateSession(options?: { serverOptions?: ServerOptions; waitForPending?: boolean; timeoutMs?: number; }): Promise ``` ##### Parameters | Parameter | Type | Default | Description | | :--- | :--- | :--- | :--- | | `serverOptions` | `ServerOptions` | undefined | Required for server-side (SSR) session invalidation. Provides the `{ req, res }` context to clear cookies on the server. | | `waitForPending` | `boolean` | `true` | When active, the SDK ensures in-flight requests finish before deleting cookies. | | `timeoutMs` | `number` | `5000` | Maximum time in milliseconds to wait for pending requests before forcing a logout. | ##### Lifecycle and behavior To ensure data integrity, `invalidateSession()` performs the following steps in order: 1. Freeze queue: the SDK stops accepting new actions to prevent race conditions during logout. 2. Synchronize requests: if `waitForPending` is `true`, then the SDK waits for active network requests to finish. 3. Purge credentials: the `frontastic-session` and `__rememberMe` cookies are deleted from storage. 4. Reset state: the internal queue is restarted, preparing the SDK for a fresh login. ##### Client-side usage Implement this standard client-side logout in your logout handler to ensure that the browser is fully cleared of session data before redirecting the user to the login page. ```ts title="Client-side logout handler" import { sdk } from '../sdk'; async function handleLogout() { // 1. Call your backend logout action const response = await sdk.callAction({ actionName: 'account/logout', }); if (!response.isError) { // 2. Invalidate the session (clears cookies, waits for pending requests) await sdk.invalidateSession(); // 3. Redirect to login page router.push('/login'); } } ``` ##### Server-side usage For server-side rendering (SSR) contexts, pass the request and response objects to the `serverOptions` parameter. This ensures that cookies are cleared on the server. ```ts title="Server-side logout handler" import type { IncomingMessage, ServerResponse } from 'http'; import { sdk } from '../sdk'; async function handleLogout(req: IncomingMessage, res: ServerResponse) { const response = await sdk.callAction({ actionName: 'account/logout', serverOptions: { req, res }, }); if (!response.isError) { await sdk.invalidateSession({ serverOptions: { req, res }, }); } } ``` ##### Custom timeout If your application has long-running requests, then you can extend the timeout period by specifying the `timeoutMs` option. ```ts title="Waiting up to 10 seconds for pending requests" await sdk.invalidateSession({ timeoutMs: 10000, }); ``` ##### Skip waiting for pending requests For scenarios where immediate logout is the preferred process, you can disable waiting for pending requests. ```ts title="Not waiting for pending requests" await sdk.invalidateSession({ waitForPending: false, }); ``` ## Related pages - [Area overview page with navigation](/frontend-development.md) - [Previous page: Installing the Frontend SDK](/frontend-development/installing-the-frontend-sdk.md) - [Next page: Developing SDK integrations](/frontend-development/developing-sdk-integrations.md) - [Search documentation and API specs](/search.md)