Was this page helpful?

Live preview - Live updates

Table of contents

Overview

Live updates is an advanced live preview feature that allows you to preview your changes without clicking the "Refresh preview" button. Whenever content is updated, the changes are immediately displayed in the live preview pane.

Setup

To enable live updates, it is required to set up live preview first.

Implementation with Vanilla JS and React

  1. Initialize the live preview SDK with the live preview provider.
import { ContentfulLivePreview } from '@contentful/live-preview';

ContentfulLivePreview.init({
  locale: 'en-US', // This is required and allows you to set the locale once and have it reused throughout the preview
  enableInspectorMode: false, // This allows you to toggle the inspector mode which is on by default
  enableLiveUpdates: false, // This allows you to toggle the live updates which is on by default
  debugMode: false, // This allows you to toggle the debug mode which is off by default
  targetOrigin: 'https://app.contentful.com', // This allows you to configure the allowed host of the live preview (default: ['https://app.contentful.com', 'https://app.eu.contentful.com'])
});
import { ContentfulLivePreviewProvider } from "@contentful/live-preview/react";

const App = ({ Component, pageProps }) => (
  <ContentfulLivePreviewProvider
    locale="en-US" // This is required and allows you to set the locale once and have it reused throughout the preview
    enableInspectorMode // This allows you to toggle the inspector mode which is on by default
    enableLiveUpdates // This allows you to toggle the live updates which is on by default
    debugMode // This allows you to toggle the debug mode which is off by default
    targetOrigin="https://app.contentful.com" // This allows you to configure the allowed host of the live preview (default: ['https://app.contentful.com', 'https://app.eu.contentful.com'])
  >
    <Component {...pageProps} />
  </ContentfulLivePreviewProvider>
);
  1. Import the useContentfulLiveUpdates hook and pass the original and full (untransformed) API response data to it. The hook then returns the live updated data in real time. See an example in the code snippet below:
For live updates when using GraphQL, it is necessary to fetch sys.id and __typename in your query.
import { ContentfulLivePreview } from '@contentful/live-preview';

/**
 * Subscribe to data changes from the Editor, returns a function to unsubscribe
 * Will be called once initially for the restored data
 */
const unsubscribe = ContentfulLivePreview.subscribe({
  data, //the JSON response from the CPA for an entry/asset or an array of entries (or assets)
  locale,
  callback, //is a function to be called when the entry/asset is updated in Contentful to tell the frontend to update the preview. This callback is what makes the frontend update instantaneously when typing in a field in the editor.
});
import { useContentfulLiveUpdates } from '@contentful/live-preview/react';

const updatedEntries = useContentfulLiveUpdates(entries);

Implementation with Next.js app router

  1. Create a Next.js client component where you initialize the ContentfulLivePreviewProvider from the SDK.
"use client";

import { ContentfulLivePreviewInitConfig } from "@contentful/live-preview";
import { ContentfulLivePreviewProvider } from "@contentful/live-preview/react";
import { PropsWithChildren } from "react";

export function ContentfulPreviewProvider({
  children,
  ...props
}: PropsWithChildren<ContentfulLivePreviewInitConfig>) {
  return (
    <ContentfulLivePreviewProvider {...props}>
      {children}
    </ContentfulLivePreviewProvider>
  );
}

Once the provider is set up in the client component, you can wrap your server component app with it:

import { ContentfulPreviewProvider } from "../components/contentful-preview-provider";

export default function Home() {
  const { isEnabled } = draftMode();
  return (
    <ContentfulLivePreviewProvider
      locale="en-US" // This is required and allows you to set the locale once and have it reused throughout the preview
      enableInspectorMode // This allows you to toggle the inspector mode which is on by default
      enableLiveUpdates // This allows you to toggle the live updates which is on by default
      debugMode // This allows you to toggle the debug mode which is off by default
      targetOrigin="https://app.contentful.com" // This allows you to configure the allowed host of the live preview (default: ['https://app.contentful.com', 'https://app.eu.contentful.com'])
    >
      <main>...</main>
    </ContentfulLivePreviewProvider>
  );
}

For a full example visit the examples directory on Github.

  1. The useContentfulLiveUpdates hook needs to be called in a client component:
"use client";

import { useContentfulLiveUpdates } from "@contentful/live-preview/react";

// entry has been fetched in a Server Component higher up the tree and passed down via props
export const Renderer = ({ entry }) => {
  const updatedEntry = useContentfulLiveUpdates(entry);
  return (
    <>
      <h1>{updatedEntry.fields.title}</h1>
    </>
  );
};

I don't want to use any client components

For customers who prefer not to use client components in Next.js, we recommend implementing a lightweight JavaScript script. This script is designed to trigger a revalidation process via a specified endpoint whenever changes are saved in Contentful, and then it automatically reloads the iframe. Simply place the script in the public folder:

import { ContentfulLivePreview } from '@contentful/live-preview';

ContentfulLivePreview.init({
  locale: 'en-US',
  debugMode: true,
  enableLiveUpdates: true,
});

ContentfulLivePreview.subscribe('save', {
  callback: async () => {
    const pathname = window.location.pathname;
    await fetch(`/api/revalidate?pathname=${pathname}`);
    window.location.reload();
  },
});

The revalidation endpoint located in app/revalidate/route.ts triggers the revalidation of a specific path based on a query string parameter (pathname) from the request URL:

import { revalidatePath } from 'next/cache';

function getQSParamFromURL(key: string, url: string): string | null {
  if (!url) return '';
  const search = new URL(url).search;
  const urlParams = new URLSearchParams(search);
  return urlParams.get(key);
}

export async function GET(request: Request) {
  const path = getQSParamFromURL('pathname', request.url);

  if (path) {
    revalidatePath(path);
  }
  return new Response('OK');
}

A limitation of the reload script with the revalidation endpoint is that content must be tagged with inspector mode. This ensures that the page doesn't reload unnecessarily when updates are made to fields not currently displayed. For a full example visit the examples directory on Github.

Provider configuration

The ContentfulLivePreviewProvider accepts parameters that allow you to customize your live preview SDK experience. The following options are available:

import { ContentfulLivePreviewProvider } from '@contentful/live-preview/react';

<ContentfulLivePreviewProvider
  locale="set-your-locale-here" // Required: allows you to set the locale once and have it reused throughout the preview.
  enableInspectorMode={false} // Optional: allows you to toggle inspector mode which is on by default.
  enableLiveUpdates={false} // Optional: allows you to toggle live updates which are on by default.
  targetOrigin="https://app.contentful.com" // Optional: allows you to configure the allowed host(s) of live preview (default: ['https://app.contentful.com', 'https://app.eu.contentful.com'])
  debugMode={false} // Optional: allows you to toggle debug mode which is off by default.
>

To optimize non-preview websites, it is advisable to disable live preview functionality by setting both enableInspectorMode and enableLiveUpdates to "false". By doing so, any specific data related to live preview, such as data-attributes, is removed.

Known issues and limitations

  • GraphQL filters (e.g. filters in the Array field type) or filtering using the select query parameter on the Content Preview API (CPA).
  • We currently do not support multiple locales within a single GraphQL query or a single CPA response. Therefore, the withAllLocales chain modifier of the JS Client SDK is not supported.
  • Live updates works only with untransformed data. Ensure that the response from the CPA or GraphQL is provided to the hook in its full and original form, with any potential transformations applied afterwards.
  • Cross-space content has no support with live updates. We only support removing or resorting resource links.