Vue Storefront is now Alokai! Learn More
Usage

Usage

This documentation covers the standalone Contentful integration and does not describe all the capabilities the Alokai ↔ Contentful setup offers. If your project is using Alokai Contentful Module, we recommend visiting its documentation instead - it provides information on unified data structure, ready-made components, and a more streamlined developer experience.

Alokai integration for Contentful ships with a framework-agnostic Typescript SDK. You can use it to:

Before you read

Visit Alokai SDK documentation to learn how to access sdk in both Next and Nuxt.

Fetching entry by ID

To fetch a single entry by ID, you can use the getEntry method.

const entry = await sdk.contentful.getEntry('5wrUZjR3uaDNedfSmYRkkB');

Fetching entry collections

Alternatively, you can use the getEntries method. It should be your primary method for fetching content entries. It allows you to build sophisticated search queries and fetch a collection of entries.

const entries = await sdk.contentful.getEntries({
  content_type: 'page',
  'fields.[<some_field>]': '<some_field_value>'
});

When working with the return value of the getEntries method, we recommend extracting the nested items property from it. It will make things such as working with the Live Preview easier.

const { items } = await sdk.contentful.getEntries({ ... });

Using Typescript IntelliSense

Thanks to the effort of the Contentful team and their amazing Typescript SDK, our SDK methods such as getEntries are fully typed. Therefore, building even the most sophisticated search queries can be a piece of cake with the Typescript IntelliSense in your IDE.

sdk methods suggestions

Initializing Live Preview

To enable Live Preview for individual components or whole pages, use the initLivePreview() utility method.

By default, Alokai sets the X-Frame-Options: DENY header, which prevents the storefront from being embedded in iframes — blocking Contentful Live Preview. To allow Live Preview, set the following variable in your frontend .env file:

NEXT_PUBLIC_DISABLE_X_FRAME_OPTIONS_HEADER=true

This guide assumes the preview URLs you have defined for your content types include the entryId query parameter.

http://localhost:3000?entryId={entry.sys.id}
page.tsx
import type { SearchParams } from 'nuqs/parsers';
import { getSdk } from '@/sdk';
import LivePreview from './live-preview';

type PageProps = {
  content: any,
  params: {
    slug?: string[];
  };
  searchParams: SearchParams;
};

export default async function ContentfulPage(props: PageProps) {
  const sdk = await getSdk();

  const content = props.content ?? await getContent();

  async function rerender(content: any) {
    "use server"
    return <ContentfulPage {...props} content={content} />
  }

  async function getContent() {
    const content = await sdk.contentful.getEntry(props.searchParams.entryId, {
      locale: 'en',
    });

    return content;
  }

  return (
    <>
      <div id="ssr-content">
        {/* your content goes here */}
      </div>
      <LivePreview initialData={content} locale="en" rerender={rerender} />
    </>
  );
}
live-preview.tsx
'use client';
import { ReactNode } from 'react';
import { useEffect, useState } from 'react';

import { useSdk } from '@/sdk/alokai-context';

export interface LivePreviewProps {
  /**
   * Raw initial data coming from the Contentful
   * Contentful needs it to initialize the live preview
   */
  initialData: any;
  /**
   * Contentful locale
   */
  locale: string;
  /**
   * The server callback function to be called when the content is updated
   */
  rerender: (content: any) => Promise<ReactNode>;
}

export default function LivePreview({
  initialData,
  rerender,
  locale
}: LivePreviewProps) {
  const sdk = useSdk();
  const [previewContent, setPreviewContent] = useState<ReactNode>(null);
  
  useEffect(() => {
    sdk.contentful.utils.initLivePreview(initialData, {
      locale,
      callback: async (updatedContent) => {
        setPreviewContent(await rerender(updatedContent));
      }
    });
  }, []);
  
  useEffect(() => {
    const ssrContent = document.getElementById('ssr-content');
    if (previewContent && ssrContent) {
      /**
       * Hide the old SSR content when the preview is ready
       */
      ssrContent.style.display = 'none';
    }
  }, [previewContent]);
  
  return previewContent;
}