Using the frontend SDK

Learn about using various features of the Frontend SDK.

Getting started

Install the SDK

The presence of the SDK, its integrations, and dependencies in commercetools Frontend projects may vary based on when the project was created and whether it's tailored for B2C or B2B Composable Commerce editions. Typically, these components should already be installed, configured, and ready for use right out of the box.

To confirm the SDK's setup within your project repository, inspect the sdk directory located at the packages/PROJECT_NAME/frontend/sdk/ path. The presence of this directory indicates that your project includes the SDK. By default, this folder should contain the following files:

  • index.ts
  • CommercetoolsSDK.ts template
  • composable-commerce folder for B2C projects or a composable-commerce-b2b folder for B2B projects

If the directory is not present in your commercetools Frontend project, follow these steps:

  1. Install the base SDK NPM package in your commercetools Frontend project by running yarn add @commercetools/frontend-sdk in the project directory.
    We recommend installing the latest version of this package to ensure you get all features and full compatibility with your integrations. This package is always backward compatible.

  2. The Composable Commerce integration is distributed as editable code. Clone or download the code for B2C projects from the frontend-composable-commerce repository and for B2B projects from the frontend-composable-commerce-b2b repository.

  3. From the downloaded folder, copy the contents of the src folder into your project at packages/PROJECT_NAME/frontend/sdk/composable-commerce/ for B2C projects or packages/PROJECT_NAME/frontend/sdk/composable-commerce-b2b/ for B2B projects.

  4. Check the dependencies in the package.json file of the SDK integration to ensure compatibility and install any missing packages.

  5. Add the following files to your Frontend project's sdk folder at packages/PROJECT_NAME/frontend/sdk/.

    • An index.ts file that exports the sdk instance. This file is for convention and ease of import throughout the project. All custom events that you create must also be exported from this file.

      packages/PROJECT_NAME/frontend/sdk/index.tsTypeScript
      import { sdk } from './CommercetoolsSDK';
      export { sdk };
    • A CommercetoolsSDK.ts template file.

    To ensure all event handlers are stored and triggered correctly, all parts of the SDK must operate as singletons to prevent duplication of events on construction, including integrations, the base SDK, and the template file.

    The CommercetoolsSDK.ts template file creates and exports only an instance of the extended class to ensure its own singleton behavior. This file is the single source of truth for anything related to the SDK and its integrations.

  6. Import and configure the SDK in an index location within your project. This needs to be called only once because the SDK is exported as a singleton. However, the SDK must be configured for both client-side and server-side rendering.

    The following examples import and configure the SDK in a Next.js 12 project.

    For client-side configuration, add the below to your packages/PROJECT_NAME/frontend/pages/_app.tsx file.

    packages/PROJECT_NAME/frontend/pages/_app.tsxTypeScript React
    import { AppProps } from 'next/app';
    import { useRouter } from 'next/router';
    import { sdk } from '../sdk';
    const Starter = ({ Component, pageProps }: AppProps) => {
    const router = useRouter();
    sdk.defaultConfigure(router.locale as string);
    return <Component {...pageProps} />;
    };
    export default Starter;

    For server-side configuration, add the below to your packages/PROJECT_NAME/frontend/pages/[[...slug]].tsx file in the getServerSideProps function.

    packages/PROJECT_NAME/frontend/pages/[[...slug]].tsxTypeScript React
    import { GetServerSideProps, Redirect } from 'next';
    import { sdk } from '../sdk';
    ...
    ...
    export const getServerSideProps: GetServerSideProps | Redirect = async ({
    params, locale, query, req, res
    }) => {
    sdk.defaultConfigure(locale as string);
    ...
    };

    In Next.js 13, the client-side index location is packages/PROJECT_NAME/frontend/src/app/[locale]/[[...slug]]/page.tsx and server-side is in any of the API routes or server components.

The SDK and Composable Commerce integration is set up now.

Configure the SDK

The configure method is defined on the base SDK main class 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 Currency Code. For example, EUR. For more information, see supported currencies.

  • 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 of three months.

  • cookieHandlingOverride - CookieManager - Optional. This option gives the user the ability to extend or override the default base SDK's CookieHandler.
    The following code example shows how to extend the default cookie handling using the defaultConfigure method in the SDK template file.

    Example code to specify custom cookie handling logicTypeScript
    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);
    },
    },
    });

Add SDK integrations

It is possible to extend the SDK with the integrations you develop. To do so, set up the integrations in the CommercetoolsSDK constructor, passing the SDK instance like the ComposableCommerce instance. For example:

Initialize an integration in the SDKTypeScript
//.... 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:

Add custom integration events type using intersectionTypeScript
class CommercetoolsSDK extends SDK<ComposableCommerceEvents & CustomIntegrationEvents> {
...
}

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 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 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: "<string>" } 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: "<string>" } } 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 mistakingly 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 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, lets 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:

    Custom events type definitionTypeScript
    // 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:

    Extend the base SDK type with custom events typeTypeScript
    // 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<ComposableCommerceEvents & MyCustomEvents> {
    ...
    }
    ...
  3. Implement the MarketingBanner React component. In this example, we're making a simple banner component with an image.

    MarketingBanner React component implementation with event handlersTypeScript React
    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 <Image src={imageSrc} onClick={() => clickHandler(marketingId)} />;
    };
    export default MarketingBanner;

    We define a function named marketingBannerClickedHandler that takes a parameter event of class Event 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 hook is 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.