Install Live Preview
Install Live Preview so your stack can read content through Contentstack's preview API, which is where drafts come from. It's two changes to your app: a live_preview block on the stack you already have, and a call to ContentstackLivePreview.init in the browser. The Studio canvas uses the first one.
The example on this page is the Blog stack, in North America, and the Next.js App Router app whose stack is in lib/contentstack.ts. The canvas shows the Blog post template, previewing AI 101.
Prerequisites
- The Delivery SDK stack in
lib/contentstack.ts. Thelive_previewblock goes on that samecontentstack.stackcall. See Install the Delivery SDK. - A preview token. It's a different value from the delivery token. See What you need in your stack.
- Your region's preview host. It's a different address from the delivery host.
- Whether your templates render on the client or on the server, because the browser setup differs. See CSR or SSR.
What Live Preview does for Studio
The live_preview block points your stack at Contentstack's preview API, which is a different service from the delivery API. Inside Studio's canvas, the Studio SDK reads the preview hash from the canvas URL and passes it to your stack's livePreviewQuery.
Live Preview Utils, the package @contentstack/live-preview-utils, is a separate part. The Studio SDK doesn't use it, and never calls ContentstackLivePreview.
Faster ways to do this
- Skill, for the full install. Ask your agent to install Studio, and it uses
install-studio. It sets up Live Preview along with the Delivery SDK and the Studio SDK. It wraps Live Preview so a Live Preview failure can't stop the Studio SDK starting. - Skill, for an app that has the Delivery SDK already. Ask your agent to add Live Preview, and it uses
install-live-preview. It reads the stack's Live Preview setting before it changes anything.
See What are skills? No CLI command installs Live Preview.
Install Live Preview Utils
npm install @contentstack/live-preview-utils
With Yarn or pnpm, run yarn add or pnpm add with the same package name.
Add the live_preview block to your stack
-
Add the preview token to your environment file:
NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN=your_preview_tokenRead the preview token from an environment variable, and never commit it.
-
In
lib/contentstack.ts, addlive_previewto thecontentstack.stackcall:import contentstack from "@contentstack/delivery-sdk";export const stack = contentstack.stack({apiKey: process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY!,deliveryToken: process.env.NEXT_PUBLIC_CONTENTSTACK_DELIVERY_TOKEN!,environment: process.env.NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT!,live_preview: {enable: true,// Read the token from the environment. Never commit it.preview_token: process.env.NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN!,// The preview API, which is a different address from the delivery one.host: "rest-preview.contentstack.com",},}); -
Set
hostto your region's preview host. The example usesrest-preview.contentstack.com, the North America host. It doesn't work for a stack in another region, so use the host that Contentstack's regions docs list for yours. Don't set it to your delivery host, because drafts come from a different service.
If your app calls livePreviewQuery on this stack anywhere else, give the Studio SDK its own stack instance, built from the same credentials. Studio calls livePreviewQuery on the stack you pass it, so both would share its state.
Start Live Preview in the browser
Call ContentstackLivePreview.init once, in the browser, before any route renders. Calling it twice breaks Live Preview. Wrap it in try and catch, so an error there doesn't stop the studioSdk.init call below it from running.
import ContentstackLivePreview, { IStackSdk } from "@contentstack/live-preview-utils";
import { stack } from "@/lib/contentstack";
try {
ContentstackLivePreview.init({
// Turn Live Preview on.
enable: true,
// false: your app refetches on onEntryChange. true: Contentstack reloads the page.
ssr: false,
// "builder" for Visual Editor. "preview" for the Live Preview panel only.
mode: "builder",
// The config of the stack in lib/contentstack.ts, with its live_preview block.
stackSdk: stack.config as IStackSdk,
stackDetails: {
apiKey: process.env.NEXT_PUBLIC_CONTENTSTACK_API_KEY!,
environment: process.env.NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT!,
},
// The Contentstack app for your region. This is North America.
clientUrlParams: {
host: "app.contentstack.com",
},
// Show the Edit button on your site inside Live Preview.
editButton: {
enable: true,
},
});
} catch (err) {
console.warn("Live Preview init failed. Continuing without it.", err);
}
What each option does:
| Option | What it does | In the example |
|---|---|---|
enable | Turns Live Preview on. Set it to false to turn it off without removing the call. | true |
ssr | How your page updates when an author edits an entry. With false, Live Preview fires onEntryChange and your app refetches. With true, Contentstack reloads the whole page with the new preview hash in the URL, and onEntryChange doesn't fire. Defaults to true. | false, because the Blog app refetches in onEntryChange |
mode | "builder" turns on Visual Editor, which needs your page to carry data-cslp tags. "preview" is the Live Preview panel only. Defaults to "preview". | "builder" |
stackSdk | The config of your Delivery SDK stack, stack.config. Live Preview writes the preview hash into it, so your stack's next fetch returns drafts. You need it when ssr is false. | stack.config from lib/contentstack.ts |
stackDetails | Your stack's API key and environment. Visual Editor uses them to open the right entry. | The Blog stack's API key, and the environment from NEXT_PUBLIC_CONTENTSTACK_ENVIRONMENT |
clientUrlParams.host | The address of the Contentstack app that opens your site. Defaults to app.contentstack.com, the North America app. For a stack in another region, use that region's app address, such as eu-app.contentstack.com. | app.contentstack.com |
editButton.enable | Shows the Edit button on your site when it opens inside Live Preview. Defaults to true. | true |
ContentstackLivePreview.init is Contentstack's API. These are the options this setup needs. For every option, see Contentstack's Live Preview Utils docs, for the version you install.
On a server-rendered route, Studio needs one more thing from you. It reads the preview hash from the searchQuery you pass to fetchCompositionData, from its hash or live_preview parameter, and passes it to your stack's livePreviewQuery. Studio only calls livePreviewQuery when the request carries a hash, so otherwise your stack keeps its own Live Preview setup. See Render on the server.
To make a template refetch when an author saves an entry, wire onEntryChange. See Refresh the template when an entry changes on the client, or Render on the server.
Check the preview token is set
Log the preview token that lib/contentstack.ts reads, once, and check it isn't undefined. Remove the log when you're done.
console.log(process.env.NEXT_PUBLIC_CONTENTSTACK_PREVIEW_TOKEN);
The check that the canvas shows a draft waits until the canvas route is mounted. It's in Check a section on the canvas.
Next, install the Studio SDK in the same module: Install the Studio SDK.
If it doesn't work
The delivery token is in preview_token
The preview token and the delivery token are different values. Put the preview token in preview_token. See What you need in your stack.
The preview host is the delivery host
Drafts come from the preview API, which is a different address from the delivery API. Set live_preview.host to your region's preview host, not the host you set on the stack.
The preview host is for another region
The North America preview host, rest-preview.contentstack.com, doesn't work for a stack in another region. Use the preview host that Contentstack's regions docs list for your region.
The preview token is undefined at runtime
The variable has the wrong prefix for your framework, or the dev server started before you added it. See A value is undefined at runtime.
The Studio SDK doesn't start after you add Live Preview
An error in ContentstackLivePreview.init stops the code after it, including studioSdk.init. Wrap the call in try and catch, as in Start Live Preview in the browser. Check, too, that your app calls it only once.
Your own livePreviewQuery calls clash with Studio's
Studio calls livePreviewQuery on the stack you pass it, so your calls and Studio's share that stack's state. Build a second stack from the same credentials, and pass that one to the Studio SDK.