The Live Preview Utils SDK version 4 allows you to listen to entry change events triggered by the Contentstack app and update your website in real time. You can also configure the “Edit” button functionality to enhance collaboration and content editing workflows.
To install the live-preview-utils package via npm, run the following command:
Alternatively, include the live-preview-utils package directly in your website’s HTML code:
If you initialize the SDK using this snippet, do not initialize it again in your app bundle on the same page.
Initialize the SDK to enable communication between your site and Contentstack:
The init() method initializes the Live Preview Utils SDK by setting up the necessary event listeners. It accepts a configuration object as a parameter. The following options are available for the configuration.
| Type | Default | Optional |
| boolean | true | yes |
The enable property determines whether Live Preview communications are enabled.
| Type | Default | Optional |
| boolean | true | yes |
The ssr property determines the data-update strategy for previewed content whenever you change entry content. It depends on whether your app is SSR or CSR.
If you set the property to true, your app or website is rendered from the server (SSR), and a request is sent for a fresh HTML page every time you edit content.
If you set the property to false, the app is rendered from the client side (CSR). Your framework, such as React, fetches the data and reloads the existing page.
Note: For CSR mode, stackSdk is required, so Contentstack automatically switches the mode to CSR when you pass this object. This config overrides the default behavior.
| Type | Default | Optional |
| string | preview | yes |
The mode property specifies whether the site is editable in the Live Preview or Visual Builder environment.
If set to preview, clicking the hovered Edit button navigates to the Contentstack Live Preview panel.
If set to builder, clicking the Start Editing button navigates to the Contentstack Visual Builder. The site still functions in the Live Preview panel even when set to builder.
The editButton object lets you manage the Edit button both within and outside the Live Preview portal. It offers the following:
The editButton object contains four keys:
| Type | Default | Optional |
| boolean | true | no |
Specifies whether to display the Edit button. Boolean, with a value of true or false.
| Type | Default | Optional |
| array | [ ] | yes |
Excludes the editButton from either inside or outside the Live Preview portal for certain conditions. Array, with any of the following string values:
Note: Even if you exclude the Edit button for Live Preview, you can add the cslp-buttons query parameter to your website URL to display the Edit button outside a Live Preview-enabled website.
| Type | Default | Optional |
| boolean | true | yes |
Overrides the cslp-buttons query parameter. Set it to true or false to enable or disable the Edit button option.
| Type | Default | Optional |
| string | top | yes |
Places the Edit button in one of eight predefined positions within or over the Live Preview portal: left, right, top-left (or top), top-right, top-center, bottom-left (or bottom), bottom-right, and bottom-center.
Note: The default position is top. In a collaborative environment, you can also position the Edit button manually by applying the data-cslp-button-position attribute to the HTML tag with one of the position values.
For example:
ContentstackLivePreview.init({
...
editButton: {
enable: true,
exclude: ["outsideLivePreviewPortal"],
includeByQueryParameter: false,
position: 'top-right',
}
});| Type | Default | Optional |
| boolean | undefined (off) | yes |
Enables Live Preview behavior when your site runs outside the Contentstack iframe — that is, on the live site itself rather than embedded in the Live Preview or Visual Builder panel. Set to true to enable.
The editInVisualBuilderButton object lets you manage the Start Editing button outside Visual Builder. It offers the following:
The editInVisualBuilderButton object contains two keys:
| Type | Default | Optional |
| boolean | true | yes |
Specifies whether to display the Start Editing button. Boolean, with a value of true or false.
| Type | Default | Optional |
| string | bottom-right | yes |
Places the Start Editing button in one of four predefined positions: top-left, top-right, bottom-left, and bottom-right.
Use this option when hovering or clicking a field in your app does nothing — no outline appears and the Edit button does not show. This typically happens when another element, such as a navigation overlay, image layer, or layout spacer, sits on top of the field and captures the mouse event instead.
Enabling overlayPropagation tells the SDK to look through stacked elements at the cursor position to find the field underneath. It works in both Visual Builder and the standalone Live Preview Edit button.
Tip: When to enable: turn this on only if you notice fields that do not respond to hover or click in your specific app layout. It is off by default.
The overlayPropagation object contains one key:
| Type | Default | Optional |
| boolean | false | yes |
Set to true to let the SDK detect fields that are visually covered by other elements.
For example:
ContentstackLivePreview.init({
...
overlayPropagation: {
enable: true,
}
});| Type | Default | Optional |
| boolean | true | yes |
When enable is set to false and cleanCslpOnProduction is set to true, the data-cslp attributes are removed from the website.
The stackDetails object contains stack-related information that helps redirect to the corresponding entry whenever you use edit tags within your website. If you do not use live edit tags, you do not need the stackDetails property.
stackDetails {
apiKey: string
environment: string
}The API key of the concerned stack.
| Note: This is required if you are using live edit tags. | |
| Type | Optional |
| string | yes (no, if you are using edit tags) |
The environment name of the concerned stack.
| Type | Optional |
| string | yes |
The clientUrlParams object contains the URL information of the stack that holds your webpage content. By default, the configuration is set for the NA region.
{
protocol: "https",
host: "app.contentstack.com",
port: 443,
}{
protocol: "https",
host: "eu-app.contentstack.com",
port: 443,
}Pass the clientUrlParams object only if you need to modify the URL.
The stackSdk object represents the Stack class returned by the Contentstack.Stack() method. It is required for Client-Side Rendering (CSR), because the Live Preview hash and content type UID are injected into the Stack class.
The onLiveEdit method modifies the content inside the Live Preview panel as soon as a change is made in the entry. It runs a single API request to retrieve draft content and display the changes in the Live Preview panel.
Note: The onLiveEdit method does not fetch published content and applies only in Client-Side Rendering (CSR) mode.
For CSR, the framework handles data collection and rendering, so create a function, such as updateData, to fetch data and pass it to onLiveEdit. The method runs updateData whenever new data is available. In a React app, call onLiveEdit inside useEffect and pass the updateData function to it.
// utils.js
...
export const onLiveEdit = ContentstackLivePreview.onLiveEdit;
...
// Footer.js
import React from "react";
import ContentstackLivePreview from "./utils.js";
const Footer = () => {
const [data, setData] = React.useState({});
const updateData = () => {
const fetchedData = SomeCallToGetData();
setData(fetchedData);
};
React.useEffect(() => {
ContentstackLivePreview.onLiveEdit(updateData);
}, []);
return <div>{data.company_name}</div>;
};For CSR, the framework handles data collection and rendering, so create a function responsible for fetching and storing data, such as updatePage(), and pass it to onEntryChange(). The method runs the function whenever new data is available.
Note:This function works only when ssr is set to false, indicating a CSR application.
// utils.js
...
export const onEntryChange = ContentstackLivePreview.onEntryChange;
...
// Footer.js
import React from "react";
import ContentstackLivePreview from "live-preview-utils";
const Footer = () => {
const [data, setData] = React.useState({});
const updateData = () => {
const fetchedData = SomeCallToGetData();
setData(fetchedData);
};
React.useEffect(() => {
ContentstackLivePreview.onEntryChange(updateData);
}, []);
return <div>{data.company_name}</div>;
};Note: To make onEntryChange behave like onLiveEdit, use the optional parameter skipInitialRender: true, which calls the Contentstack API only once.
For example:
onEntryChange(fetchData, { skipInitialRender: true });The setPageContext() method tells Visual Builder which entry the current page renders, so the Start Editing button and the init handshake target the correct entry, even when a page is served from a custom URL that the SDK cannot map to an entry on its own.
The context is used in two places: on the initial init handshake, so Visual Builder can confirm whether the entry it has open matches the page rendered in the iframe; and on the Start Editing button click, so it can navigate to the correct entry. Because init() run before your async data fetch resolves, calling setPageContext() once your entry is available sends the context to Visual Builder so it can update its current entry.
Place the call alongside your existing addEditableTags call, since both reference the same entry object.
| Parameter | Type | Description |
| context.entryUid | string | UID of the entry the current page renders |
| context.contentTypeUid | string | UID of that entry’s content type |
For example:
import ContentstackLivePreview from "@contentstack/live-preview-utils";
import Utils from "@contentstack/utils";
// In your page component (for example, inside useEffect, once the entry is fetched)
Utils.addEditableTags(entry, "blog_post", true, "en-us");
ContentstackLivePreview.setPageContext({
entryUid: entry.uid,
contentTypeUid: "blog_post",
});Note: Inside the Visual Builder or Live Preview iframe, the context is also sent to Contentstack through a post message. Outside an iframe, the context is stored locally and used only to build the Start Editing redirect URL.
Alternative ways to supply page context
If you cannot call setPageContext() directly — for example, when no JavaScript hook is available for injecting runtime values — the SDK resolves the page context from these sources, in order of precedence:
window.__CS_PAGE_CONTEXT__ = {
entryUid: "entry-123",
contentTypeUid: "blog_post",
};<meta name="contentstack:entry-uid" content="entry-123" />
<meta name="contentstack:content-type-uid" content="blog_post" />Meta tags are a useful fallback for frameworks that render <meta> natively (for example, Next.js App Router metadata / generateMetadata(), or Nuxt useHead()) and for sites with a strict Content Security Policy that blocks inline scripts but allows meta tags.
The hash property returns the Live Preview hash of the entry. It returns an empty string if the page is not opened in the Live Preview pane.
Note: In SSR mode, the hash may not be populated automatically. To extract and use the hash manually, refer to Utilize the Live Preview Hash in the Set Up the Website section.
For example:
console.log(ContentstackLivePreview.hash); // "hash"The config property returns the following properties and their values: