This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.

commercetools Frontend SDK

The commercetools Frontend SDK is an event management tool that allows flexible and customizable frontend development. It also allows creating custom integrations that are backend-agnostic and backward-compatible. The commercetools Frontend SDK can be extended with additional SDKs and integrations that expose commercetools Frontend API integrations.

Install and set up the SDK

The SDK is released as an npm package. To install it in your commercetools Frontend project, follow these steps:

  1. Run yarn add @commercetools/frontend-sdk.
  2. Run yarn add @commercetools/frontend-domain-types.
  3. Set up the SDK and any additional integration packages in the same location, as shown in the example below.

The SDK and its integrations must behave as singletons to prevent integrations from creating repeated events and multiple configuration calls.

It is recommended to use the latest version of all packages related to commercetools frontend SDK. The @commercetools/frontend-sdk package will always be backward compatible, therefore having the latest version ensures you have all features and full compatibility with all your integrations.

Below is a template provided to use with the SDK and integrations to ensure singleton behaviour.

packages/<project>/frontend/sdk/CommercetoolsSDK.tsTypeScript
import { SDK } from '@commercetools/frontend-sdk';
import {
ComposableCommerce,
ComposableCommerceEvents,
} from '@commercetools/frontend-composable-commerce';
// Add other integration's custom events to the SDK's generic type here,
// by extending ComposableCommerceEvents with their type using an intersection.
// For example, <ComposableCommerceEvents & OtherEvents>.
// You may also add your own custom events.
class CommercetoolsSDK extends SDK<ComposableCommerceEvents> {
composableCommerce!: ComposableCommerce;
// Add your other integrations here.
constructor() {
super();
this.composableCommerce = new ComposableCommerce(this);
// Initialize your other integrations here.
this.on('errorCaught', (event) => {
// Handle any integrations errors caught by the SDK globally.
// For example, log error, fire notification, etc.
console.log('SDK error: ', event.data);
});
// Set up any other custom global event handlers here.
// Ensure types are created and added to the SDK generic type
// if specific to your project.
}
}
// Create a single instance of the SDK.
const sdk = new CommercetoolsSDK();
// Export only the instance to serve as a singleton throughout the project.
export { sdk };

The previous example creates and exports an instance to ensure singleton behavior. However, the CommercetoolsSDK.ts template file must be the single source of truth for anything related to the SDK and integrations. Therefore, it is recommended to store CommercetoolsSDK.ts and index.ts in a folder packages/<project>/frontend/sdk for convention and ease of import.

packages/<project>/frontend/sdk/index.tsTypeScript
import { sdk } from './CommercetoolsSDK';
export { sdk };

Configure the SDK

Import and configure the SDK in an index location within your project, this needs to be called only once since the SDK is exported as a singleton. However, the SDK must be configured for both client-side and server-side rendering. The following example imports and configures the SDK in a Next.js project.

packages/<project>/frontend/pages/_app.tsxTypeScript React
import { AppProps } from 'next/app';
import { sdk } from '../sdk';
sdk.configure({
locale: 'de-DE',
currency: 'EUR',
endpoint: 'EXTENSION_RUNNER_HOSTNAME',
});
const Starter = ({ Component, pageProps }: AppProps) => {
return <Component {...pageProps} />;
};
export default Starter;

For information on the extension runner hostname, see Main development concepts.

If needed, pass the useCurrencyInLocale property to the configure method. The default value is false.

Set useCurrencyInLocale to trueTypeScript React
sdk.configure({
locale: 'de-DE@EUR',
currency: 'EUR',
endpoint: 'EXTENSION_RUNNER_HOSTNAME',
useCurrencyInLocale: true,
});

You can import the configuration properties from the .env file, a .config file, or the getServerSideProps call in Next.js for server-side rendering.

packages/<project>/frontend/pages/[[...slug]].tsxTypeScript React
import { GetServerSideProps, Redirect } from 'next';
import { mapSDKLanguage } from 'project.config';
import { sdk } from '../sdk';
type SlugProps = {
...
};
export default function Slug({ data }: SlugProps) {
...
}
export const getServerSideProps: GetServerSideProps | Redirect = async ({ params, locale, query, req, res }) => {
sdk.configure({
locale: mapSDKLanguage(locale),
currency: 'EUR',
endpoint: (process.env.NEXT_PUBLIC_FRONTASTIC_HOST ?? ”https://my.staging.server/frontastic”).split('/frontastic')[0],
});
...
};

If the project uses only the SDK, no further configuration is required. If the project also uses integrations, you can call them from packages/<project>/frontend/sdk.

The following example configures a Next.js project that uses the @commercetools/frontend-composable-commerce integration. The getSettings function is called on button click and applies the project settings. On component mount, the useEffect React lifecycle hook adds an event handler to log the result of the fetch to the console. On component unmount, the event handler is cleaned up.

Next.js page using the frontend-composable-commerce integrationTypeScript React
import { NextPage } from 'next';
import React, { useEffect, useState } from 'react';
import App from '../../components/App';
import HorizontalSpacer from '../../components/horizontalSpacer';
import { sdk } from '../../sdk';
import Button from 'src/components/form/button';
import { ProjectSettings } from '@commercetools/frontend-domain-types/ProjectSettings';
const ExamplePage: NextPage = () => {
const [projectSettings, setProjectSettings] = useState<ProjectSettings>();
const [loading, setLoading] = useState(false);
const projectSettingsReturnedEvent = (
event: Event<
'projectSettingsReturned',
{
settings: unknown;
}
>
) => {
// Access the commercetools Frontend project settings here.
console.log('Event projectSettingsReturned fired: ', event.data.settings);
};
useEffect(() => {
sdk.on('projectSettingsReturned', projectSettingsReturnedEvent);
return () => {
sdk.off('projectSettingsReturned', projectSettingsReturnedEvent);
};
}, []);
const getSettings = async () => {
setLoading(true);
const response = await sdk.composableCommerce.project.getSettings();
setLoading(false);
if (response.isError === false) {
setProjectSettings(response.data);
}
};
const style = { fontWeight: 'bold', textDecoration: 'underline' };
return (
<App>
<>
<h1>Example</h1>
<HorizontalSpacer />
<Button
text="TEST"
onSubmit={
projectSettings ? () => setProjectSettings(undefined) : getSettings
}
loading={loading}
/>
<HorizontalSpacer />
{projectSettings && (
<>
<>
<h2 style={style}>NAME</h2>
<p>{projectSettings.name}</p>
</>
</>
)}
</>
</App>
);
};
export default ExamplePage;

The response.isError in the getSettings function must be explicitly compared to the boolean value in non-strict projects for the narrowing to work on the SDKResponse union type. Otherwise, the error Property 'data' does not exist on type will occur on when accessing response.data. For strict projects, a simple truthy/falsy comparison such as !response.isError is sufficient.