{"id":15022411,"url":"https://github.com/contentful/live-preview","last_synced_at":"2026-03-09T02:03:52.588Z","repository":{"id":80558485,"uuid":"604202146","full_name":"contentful/live-preview","owner":"contentful","description":"Preview SDK for both the field tagging connection + live content updates","archived":false,"fork":false,"pushed_at":"2025-05-12T00:40:17.000Z","size":5529,"stargazers_count":73,"open_issues_count":4,"forks_count":16,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-05-12T01:28:37.579Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.contentful.com/developers/docs/tutorials/general/live-preview/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/contentful.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-02-20T14:52:08.000Z","updated_at":"2025-05-12T00:40:20.000Z","dependencies_parsed_at":"2024-04-15T02:23:54.506Z","dependency_job_id":"1ddde5e2-7bb6-489e-9379-56db56d52adb","html_url":"https://github.com/contentful/live-preview","commit_stats":{"total_commits":980,"total_committers":16,"mean_commits":61.25,"dds":"0.38265306122448983","last_synced_commit":"add158033b7a24c8c7b82f2e7e16a5d07f675d41"},"previous_names":[],"tags_count":322,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Flive-preview","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Flive-preview/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Flive-preview/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/contentful%2Flive-preview/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/contentful","download_url":"https://codeload.github.com/contentful/live-preview/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254464895,"owners_count":22075570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T19:57:54.994Z","updated_at":"2026-03-02T02:02:47.183Z","avatar_url":"https://github.com/contentful.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @contentful/live-preview\n\nLive preview SDK for both the inspector mode connection + live content updates by [Contentful](https://www.contentful.com/).\n\n\u003e [!IMPORTANT]\n\u003e :rocket: **Major Performance Boost for Live Updates!** (2025-02-26)\n\u003e\n\u003e We've drastically improved Live Updates, making them up to **14× faster** for complex, nested content models. Previously, these updates could take several seconds—now, with our new technical approach, they happen almost instantly.\n\u003e Enjoy a smoother, more responsive experience! :dash::sparkles:\n\u003e\n\u003e (Requirement: @contentful/live-preview \u003e= 3.0.0)\n\n\u003cdetails\u003e\n\u003csummary\u003eTable of contents\u003c/summary\u003e\n\n\u003c!-- TOC --\u003e\n\n- [Getting started](#getting-started)\n  - [Requirements](#requirements)\n  - [Installation](#installation)\n  - [Initializing the SDK](#initialize-the-sdk)\n    - [Init Configuration](#init-configuration)\n    - [Overriding Locale](#overriding-locale)\n  - [Inspector Mode](#inspector-mode-field-tagging)\n  - [Live Updates](#live-updates)\n    - [Live Updates with GraphQL](#live-updates-with-graphql)\n- [Example Integrations](#example-integrations)\n  - [JavaScript](#vanilla-javascript)\n  - [Next.js](#integration-with-nextjs)\n  - [Gatsby](#integrating-with-gatsby)\n  - [Further Examples](#further-examples)\n- [Documentation](#documentation)\n- [Code of Conduct](#code-of-conduct)\n- [License](#license)\n\u003c!-- /TOC --\u003e\n\n\u003c/details\u003e\n\n## Getting started\n\n### Requirements\n\n- Node.js: `\u003e=16.15.1`\n\nTo install live preview simply run one of the following commands.\n\n### Installation\n\n```bash\nyarn add @contentful/live-preview\n```\n\nor\n\n```bash\nnpm install @contentful/live-preview\n```\n\n### Initializing the SDK\n\nTo establish a communication between your preview frontend and Contentful, you simply need to initialize the live preview SDK. This can be done by executing the following command:\n\n```jsx\nimport { ContentfulLivePreview } from '@contentful/live-preview';\n\n...\n\nContentfulLivePreview.init({ locale: 'en-US'});\n```\n\n#### Init Configuration\n\nThe init command also accepts a configuration object that allows you to customize your live preview SDK experience. The following options are available:\n\n```jsx\nimport { ContentfulLivePreview } from '@contentful/live-preview';\n\n...\n\nContentfulLivePreview.init({\n  locale: 'set-your-locale-here', // This is required and allows you to set the locale once and have it reused throughout the preview\n  enableInspectorMode: false, // This allows you to toggle the inspector mode which is on by default\n  enableLiveUpdates: false, // This allows you to toggle the live updates which is on by default\n  debugMode: false, // This allows you to toggle the debug mode which is off by default\n  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'])\n});\n```\n\n#### Overriding Locale\n\nIt is possible to override the locale you set in the init command for a more flexible workflow. If you need to override the locale you can do so either in the getProps command like below:\n\n```jsx\nContentfulLivePreview.getProps({ entryId: id, fieldId: 'title', locale: 'fr' });\n```\n\nYou can also override it when using our useContentfulLiveUpdates hook like below:\n\n```tsx\nimport { useContentfulLiveUpdates } from '@contentful/live-preview/react';\n\n// ...\nconst updated = useContentfulLiveUpdates(originalData, { locale });\n// ...\n```\n\n### Inspector Mode (field tagging)\n\nTo use the inspector mode, you need to tag fields by adding the live preview data-attributes (`data-contentful-entry-id`, `data-contentful-asset-id`, `data-contentful-field-id`) to the rendered HTML element output.\n\nYou can do this in React via our helper function.\n\n```jsx\nimport { ContentfulLivePreview } from '@contentful/live-preview';\n...\n\n\u003ch1 {...ContentfulLivePreview.getProps({ entryId: id, fieldId: 'title' })}\u003e\n  {title}\n\u003c/h1\u003e\n```\n\n#### Outlines in Inspector Mode\n\nPer default, the inspector mode renders all available outlines despite being overlapped by other elements. If you want to not render outlines for overlapped elements, you can enable this behaviour through an experimental feature flag:\n\n```jsx\n\u003cContentfulLivePreviewProvider experimental={{ hideCoveredElementOutlines: true }} /\u003e\n```\n\n```js\nContentfulLivePreview.init({\n  // ...\n  experimental: { hideCoveredElementOutlines: true },\n});\n```\n\n### Live Updates\n\nLive updates allow you to make changes in your editor and see the updates in real time. The updates are only happening on the **client-side** and in the live preview environment of [Contentful](https://app.contentful.com).\n**Note:** Currently transformations of Contentful response data are not supported. In order for live updates to work as intended, Contentful data must be kept in its **original structure**.\n\n```tsx\nimport { useContentfulLiveUpdates } from '@contentful/live-preview/react';\n\n// ...\nconst updated = useContentfulLiveUpdates(originalData);\n// ...\n```\n\n### Live updates with GraphQL\n\nFor the best experience of live updates together with GraphQL, we recommend to provide your query information to `useContentfulLiveUpdates`.\nThis will benefit the performance of updates and provides support for GraphQL features (e.g. `alias`).\n\n```tsx\nimport gql from 'graphql-tag';\n\nconst query = gql`\n  query posts {\n    postCollection(where: { slug: \"${slug}\" }, preview: true, limit: 1) {\n      items {\n        __typename\n        sys {\n          id\n        }\n        slug\n        title\n        content: description\n      }\n    }\n  }\n`;\n\n// ...\nconst updated = useContentfulLiveUpdates(originalData, { query });\n// ...\n```\n\n### Open Entry or Asset in Editor\n\n`ContentfulLivePreview.openEntryInEditor({fieldId: string, entryId: string, locale: string})`\n\nOpens an entry in the Contentful live preview editor. This utility function allows for manual control over the editor opening process, providing flexibility for developers to integrate this action within custom UI components or events.\n\n- **fieldId** (string): The ID of the field you want to target.\n- **entryId** (string): The ID of the entry containing the field.\n- **assetId** (string): The ID of the asset containing the field.\n- **locale** (string): The locale of the content.\n\n**Usage**:\n\n```javascript\nContentfulLivePreview.openEntryInEditor({\n  entryId: 'entryId',\n  fieldId: 'fieldId',\n  locale: 'en-US',\n});\n```\n\n## Known issues and limitations\n\n### General\n\n- If the live preview SDK is used inside of another iframe than in the contentful app, it might produce errors as it can't detect the host.\n  To remove the error, you have to define the `targetOrigin` manually. ([Init Configuration](#init-configuration))\n\n### Live updates limitations:\n\n- GraphQL filters (e.g. filters in the Array field type) or filtering using the [select query parameter](https://www.contentful.com/developers/docs/references/content-preview-api/#/reference/search-parameters/select-operator) on the Content Preview API (CPA).\n- We currently do not support multiple locales within a single GraphQL query or a single CPA response.\n- Live updates works only with untransformed data. Ensure that the response from the CPA or GraphQL is provided to the hook in its original form, with any potential transformations applied afterwards.\n\n## Example Integrations\n\n### Vanilla Javascript\n\nYou can find an example in the [examples/vanilla-js](./examples/vanilla-js/) folder.\n\nBefore you initialize live preview SDK you'll want to make whatever call (REST or GraphQL API) to get the entries and assets that make up the page being requested.\n\nTo use the Contentful Live Preview SDK with [Javascript], you can use the following steps to add it to an existing project.\n\n1. Add the @contentful/live-preview package to your project\n\n```bash\nyarn add @contentful/live-preview\n```\n\nor\n\n```bash\nnpm install @contentful/live-preview\n```\n\n2. Once you've got the data from Contentful, then you can initialize the live preview. You can use the `ContentfulLivePreview` class' [init function](#init-configuration).\n\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eLive Preview Example\u003c/title\u003e\n    \u003cscript type=\"module\"\u003e\n      import { ContentfulLivePreview } from '@contentful/live-preview';\n\n      ContentfulLivePreview.init({ locale: 'en-US' });\n    \u003c/script\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\u003c/body\u003e\n\u003c/html\u003e\n```\n\n3. Then for each entry and field on which you want to use the inspector mode to show an edit button in the preview, you'll need to tag the HTML elements with the appropriate data attributes. The data attributes are `data-contentful-entry-id` and `data-contentful-field-id`. If you want to override the global locale from the init function, you can set `data-contentful-locale`.\n\nYou can use the provided helper function `getProps()`.\n\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eLive Preview Example\u003c/title\u003e\n    \u003cscript type=\"module\"\u003e\n      import { ContentfulLivePreview } from '@contentful/live-preview';\n\n      ContentfulLivePreview.init({ locale: 'en-US' });\n\n      const heading = document.getElementById('demo');\n\n      /*\n       * Example response\n       *\n       * const props = {\n       *   'data-contentful-field-id': 'fieldId',\n       *   'data-contentful-entry-id': 'entryId',\n       *   'data-contentful-locale': 'en-US',\n       *   }\n       */\n      const props = ContentfulLivePreview.getProps({ entryId: id, fieldId: title });\n\n      for (const [key, value] of Object.entries(props)) {\n        // change from hyphen to camelCase\n        const formattedName = key.split('data-')[1].replace(/-([a-z])/g, function (m, w) {\n          return w.toUpperCase();\n        });\n\n        heading.dataset[formattedName] = value;\n      }\n    \u003c/script\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003ch1 id=\"demo\"\u003eTitle\u003c/h1\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n4.To use the live updates feature you will have to subscribe for changes for **each** entry/asset, to get updates when a field is edited in Contentful.\n\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003ctitle\u003eLive Preview Example\u003c/title\u003e\n    \u003cscript type=\"module\"\u003e\n      import { ContentfulLivePreview } from '@contentful/live-preview';\n\n      const locale = 'en-US';\n\n      ContentfulLivePreview.init({ locale });\n\n      /**\n       * Subscribe to data changes from the Editor, returns a function to unsubscribe\n       * Will be called once initially for the restored data\n       */\n      const unsubscribe = ContentfulLivePreview.subscribe({\n        data, //the JSON response from the CPA for an entry/asset or an array of entries (or assets)\n        locale,\n        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 almost instantaneously when typing in a field in the editor.\n      });\n    \u003c/script\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\u003c/body\u003e\n\u003c/html\u003e\n```\n\nThat's it! You should now be able to use the Contentful Live Preview SDK with vanilla JS.\n\n### React\n\n#### Requirements\n\n- React.js \u003e=17\n\n#### Integration with Next.js\n\nYou can find an example for the NextJS Pages Router implementation in the [examples/nextjs-graphql](./examples/nextjs-graphql/) folder.\nIf you are using the app router you can look at this [example](./examples/nextjs-13-app-router-graphql/) or for using react server components only, use this [example](./examples/next-app-router-rsc/) instead.\n\nTo use the Contentful Live Preview SDK with [Next.js](https://nextjs.org), you can either use one of the Contentful starter templates, or do the following steps to add it to an existing project.\n\n1. Add the @contentful/live-preview package to your project\n\n```bash\nyarn add @contentful/live-preview\n```\n\nor\n\n```bash\nnpm install @contentful/live-preview\n```\n\n2. Initialize the SDK with the `ContentfulLivePreviewProvider` and add the stylesheet for field tagging inside `_app.tsx` or `_app.js`.\n   The `ContentfulLivePreviewProvider` accepts the same arguments as the [init function](#init-configuration).\n\n```tsx\nimport { ContentfulLivePreviewProvider } from '@contentful/live-preview/react';\n\nconst CustomApp = ({ Component, pageProps }) =\u003e (\n  \u003cContentfulLivePreviewProvider locale=\"en-US\"\u003e\n    \u003cComponent {...pageProps}\u003e\n  \u003c/ContentfulLivePreviewProvider\u003e\n)\n```\n\nThis provides the possibility to only enable live updates and inspector mode inside draft mode:\n\n```tsx\nimport { ContentfulLivePreviewProvider } from '@contentful/live-preview/react';\n\nconst CustomApp = ({ Component, pageProps }) =\u003e (\n  \u003cContentfulLivePreviewProvider\n    locale=\"en-US\"\n    enableInspectorMode={pageProps.draftMode}\n    enableLiveUpdates={pageProps.draftMode}\u003e\n    \u003cComponent {...pageProps} /\u003e\n  \u003c/ContentfulLivePreviewProvider\u003e\n);\n```\n\n3. Add field tagging and live updates to your component\n\n```tsx\nexport default function BlogPost: ({ blogPost }) {\n  const inspectorProps = useContentfulInspectorMode()\n  // Live updates for this component\n  const data = useContentfulLiveUpdates(\n    blogPost\n  );\n\n  return (\n    \u003cSection\u003e\n      \u003cHeading as=\"h1\"\u003e{data.heading}\u003c/Heading\u003e\n      {/* Text is tagged and can be clicked to open the editor */}\n      \u003cText\n        as=\"p\"\n        {...inspectorProps({\n          entryId: data.sys.id,\n          fieldId: 'text',\n        })}\u003e\n        {data.text}\n      \u003c/Text\u003e\n    \u003c/Section\u003e\n  );\n}\n```\n\n\u003e It doesn't matter if the data is loaded with getServerSideProps, getStaticProps or if you load it in any other way.\u003cbr\u003eIt's necessary that the provided information to `useContentfulLiveUpdate` contains the `sys.id` for identification and only non-transformed fields can be updated.\u003cbr\u003e(For GraphQL also the `__typename` needs to be provided)\n\n**Tip:** If you want to tag multiple fields of an entry, you can also provide initial arguments to the hook:\n\n```tsx\nexport default function BlogPost: ({ blogPost }) {\n  const inspectorProps = useContentfulInspectorMode({ entryId: data.sys.id })\n\n  return (\n    \u003cSection\u003e\n      \u003cHeading as=\"h1\" {...inspectorProps({ fieldId: 'heading' })}\u003e{data.heading}\u003c/Heading\u003e\n      \u003cText as=\"p\" {...inspectorProps({ fieldId: 'text' })}\u003e\n        {data.text}\n      \u003c/Text\u003e\n    \u003c/Section\u003e\n  )\n}\n```\n\n4. Enable draft mode\n\nWe suggest using the [draft mode](https://nextjs.org/docs/pages/building-your-application/configuring/draft-mode) and the [Content Preview API](https://www.contentful.com/developers/docs/references/content-preview-api/) for the best experience.\n\nFor a full guide checkout this [free course](https://www.contentful.com/nextjs-starter-guide/)\n\n\u003e Due some security settings the draft mode is not always shared with the iframe.\u003cbr\u003eYou can find a workaround in our [examples](./examples/nextjs-graphql/pages/api/draft.ts#L25)\n\n5. In Contentful, configure the draft URL for your Next.js application in the Content preview settings. Once you open an entry with a configured preview URL, you can use the live preview and all its features.\n\nThat's it! You should now be able to use the Contentful live preview SDK with Next.js.\n\n#### Integrating with Gatsby\n\n🚧 **Please be aware that Gatsby support is currently limited. While Inspector Mode is operational, there is a known issue with live updates not functioning as expected.**\n\n`gatsby-source-contentful` applies transformations to data received from Contentful, which affects the functionality of live updates. To ensure live updates operate properly, it's essential that Contentful data maintains its original structure. However, Inspector Mode remains fully compatible with Gatsby:\n\n```jsx\nexport default function Hero({ data }) {\n  const inspectorProps = useContentfulInspectorMode();\n\n  return (\n    \u003cSection\u003e\n      {/* Text is tagged and can be clicked to open the editor */}\n      \u003cText\n        as=\"p\"\n        {...inspectorProps({\n          entryId: data.contentful_id,\n          fieldId: 'text',\n        })}\u003e\n        {data.text}\n      \u003c/Text\u003e\n    \u003c/Section\u003e\n  );\n}\n```\n\nFor an example of inspector mode with Gatsby, you can checkout out the [examples directory](./examples/gatsby).\n\n### Further Examples\n\nFor further examples see the [./examples](./examples/) directory.\n\n## Documentation\n\n- [Developer Documentation](https://www.contentful.com/developers/docs/tutorials/general/live-preview/)\n\n## Code of Conduct\n\nWe want to provide a safe, inclusive, welcoming, and harassment-free space and experience for all participants, regardless of gender identity and expression, sexual orientation, disability, physical appearance, socioeconomic status, body size, ethnicity, nationality, level of experience, age, religion (or lack thereof), or other identity markers.\n\n[Read our full Code of Conduct](https://github.com/contentful-developer-relations/community-code-of-conduct).\n\n## License\n\nThe live preview package is open source software [licensed as MIT](./LICENSE).\n\n[contentful]: https://www.contentful.com\n[github-issues]: https://github.com/contentful/live-preview/issues\n[typescript]: https://www.typescriptlang.org/\n[react]: https://reactjs.org/\n[prettier]: https://prettier.io/\n[eslint]: https://eslint.org/\n[vite]: https://vitejs.dev/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontentful%2Flive-preview","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcontentful%2Flive-preview","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcontentful%2Flive-preview/lists"}