Edit and preview content side-by-side with our new Live Preview
Hygraph
Docs

Live preview

Hygraph Studio's Live Preview feature allows you to preview content in your frontend before it's published.

#What you can do

  • Preview your work before it goes live.

#Limitations

  • Live Preview is not compatible with native mobile applications.
  • Live Preview does not support Visual Editing.
  • Requests count against rate limits and usage of your project.

#Add a preview widget

Live preview - Add to content modelLive preview - Add to content model

To use live preview, you must first add a preview widget to a model in your schema.

  1. Navigate to the Schema builder.

  2. Select a model to add the preview widget

  3. Click on the Sidebar tab, located at the top of the screen.

  4. Select the Preview widget from the right sidebar.

  5. Complete the Preview name and the URL template fields.

  6. Click Add to save.

You can now use the live preview feature

#How to define a URL template

The exact way to build a URL template for previews depends on your website's URL structure.

Typically, you will start with your domain, then a section such as a "blog". Finally, you will use handlebars notation to include a field that is unique to the content you want to preview, to use as an identifier - usually a unique slug or the ID.

For example:

https://preview.your-domain.com/blog/{slug}

or

https://your-domain.com/blog/{slug}?preview=true

As soon as you type in the open curly brace, the system will list all the available fields for you.

We also recommend adding a secret token to the URL, which only your app and Hygraph will know.

You can also see these options in the Available fields screen section. You can use more than one of the available fields, if needed.

#Delete a preview widget

Delete a preview widgetDelete a preview widget

  1. Navigate to the Schema builder.
  2. Select the model that contains the preview widget that you want to delete.
  3. Click on the context menu for the widget, and select Remove.

#Use live preview

Follow these steps to preview your content:

  1. Navigate to the Content editor and select a content view.
  2. Click on an existing entry to edit it.
  3. Click Open live preview on the right sidebar. The preview will display to the right of the content editing screen.
  4. Make changes to the content entry and then click Save & preview.

Our live preview feature will show you a side-by-side content preview in the Hygraph content form:

Live previewLive preview

To update the preview after making additional changes, make sure to click Save & preview.

#Troubleshooting

#CSP or security header issues

Once the preview is set up, the live preview panel may display a Refused to connect message, or the console may show something like Refused to frame 'https://example.com/' because an ancestor violates the following Content Security Policy (CSP) directive: frame-ancestors 'self'.

CSP or security header issuesCSP or security header issues

If this happens, it could be due to a strict security configuration (Security Header or Content Security Policy) on your website that prevents other websites from embedding it.

To resolve this, contact your development or security team to adjust your website's security configuration.

To fix this issue, we need to verify what's causing it. Follow these steps:

  1. Navigate to the Network tab in your browser console.

  2. Search for the page you are trying to see.

  3. Under the Headers subtab, click on the Response Headers.

  4. Determine whether the security configuration matches one of the options below:

    • If the X-Frame-Options header is set, remove it from your application.

    OR

    • If the Content-Security-Policy header doesn't include the Hygraph domain, you need to add it. It should look similar to this: frame-ancestors 'self' https://*.hygraph.com.

#Stale data

If you're dealing with stale data, you need to make sure your application is reading data from the DRAFT stage, and that you don't have a caching layer when you're in preview mode.

Without this, your requests will be cached and so you will always see stale data in the UI.

Here are some recommendations:

API permissions

Make sure you define the permissions for our API correctly. You can create a token for preview and another for production.

Preview token

In your Hygraph project, go to Project Settings > Access > Permanent Auth Tokens and create a new token for preview. You need to select DRAFT as the default stage.

Once on the token page, make sure you initialize default permissions.

Production token

Repeat the process to create a token, but this time select PUBLISHED as the default stage. Make sure to also initialize default permissions.

Now, after you create the tokens, you need to update your application so you can use them.

If you are using Next.js, we recommend using Draft Mode with App Router, and for Pages Router, you can also use Draft Mode, but with a different setup.

For Remix, here's a complete guide on how to set up preview mode.

Below, you can also find guides on how to implement it for different frameworks.

#Content API endpoint

While new projects can only see this endpoint, old ones can see - and could be using - the legacy endpoint.

You can find the High Performance Content API endpoint in Project Settings > Access > API Access.

Click here to learn more about our high performance endpoint.

#Frontend implementation

To be able to use side-by-side visual preview in your frontend implementation, you have to query the GraphQL endpoint for your page in the DRAFT stage rather than the PUBLISHED stage.

Ways to query the DRAFT stage

  • Create a URL for your web app that queries the DRAFT stage of your endpoint. This could look like: https://preview.yourwebsite.com. You could also use a query parameter on the URL, like this: https://yourwebsite.com?preview=true.
  • Create a permission on another content API endpoint that by default returns the DRAFT stage in the context of preview. Use that in the web app you want to do preview with.
  • Change from PUBLISHED to DRAFT in your app based on a preview context inside your frontend.

#Next.js

In Next.js we have the concept of draftMode from the next/headers package. This mode sets a cookie in the browser to enable itself.

import { draftMode, cookies } from 'next/headers';
import { redirect } from 'next/navigation';
export async function GET(request) {
const { searchParams } = new URL(request.url);
const previewToken = searchParams.get('previewToken');
const slug = searchParams.get('slug');
// Check for a slug and for a preview token
if (!previewToken || !slug) {
return new Response('Invalid token', { status: 401 });
}
// Get the slug from Hygraph to ensure we don't run into redirect loops
const res = await fetch(process.env.HYGRAPH_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `
query SinglePage($slug: String!) {
page(where: { slug: $slug }, stage: DRAFT) {
slug
}
}
`,
variables: { slug },
}),
});
// Return the data
const { data } = await res.json();
// If the data returns in undefined or in the wrong shape, return an error
if (!data || !data.page) {
return new Response('Invalid slug', { status: 401 });
}
// Workaround for https://github.com/vercel/next.js/issues/49927
// Enable draft mode as usual
draftMode().enable();
// Update the cookie and set same site to none so we can render it inside Hygraph
const cookieStore = cookies();
const cookie = cookieStore.get('__prerender_bypass');
cookies().set({
name: '__prerender_bypass',
value: cookie?.value,
httpOnly: true,
path: '/',
secure: true,
sameSite: 'none',
});
redirect(`/${data.page.slug}`);
}

Once draftMode is set up you can amend your GraphQL queries so they can query for the DRAFT or PUBLISHED stages.

If you prefer, to make things easier so you don't need to update all your queries, you can also use the strategy we shared before, of having two tokens. If isEnabled is true, you can conditionally change the token.

In /app/page.tsx:

import { request } from 'graphql-request';
import { draftMode } from 'next/headers';
// isEnabled is true if the cookie has been set.
// See: https://nextjs.org/docs/app/building-your-application/configuring/draft-mode
const { isEnabled } = draftMode();
const query = `
query Page($slug: String!, $stage: Stage! = PUBLISHED) {
page(where: { slug: $slug }, stage: $stage) {
title
description
}
}
)`;
const variables = {
stage: isEnabled ? 'DRAFT' : 'PUBLISHED',
slug: '/about',
};
const { data: page } = await request(HYGRAPH_ENDPOINT, query, variables);

Next preview URL structure

The preview URL you set up in the sidebar configuration of your schema would look like this:

https://yourwebsite.com/api/draft?secret=MY_SECRET_TOKEN&slug={slug}

#Nuxt

Nuxt has a similar setup to Next.js and can put itself in preview mode as well. The below example is the simplest version. You will see this approach used by many CMS implementations.

Create a Nuxt plugin in the plugins folder like so: /plugins/review.ts. Nuxt will automatically read it once it starts up.

export default defineNuxtPlugin((nuxtApp) => {
const route = useRoute();
const preview = route.query.preview && route.query.preview === 'true';
if (preview) {
nuxtApp.hook('page:finish', () => {
refreshNuxtData();
});
}
return { provide: { preview } };
});

This plugin looks at the query string ?preview=true and based on that provides a global preview variable to the whole app.

The variable $preview is now available in all components.

In /pages/about.vue, you can do the following to decide what stage you want to query:

<script setup>
import { request } from "graphql-request";
// See previous code block for how to enable $preview
const { $preview } = useNuxtApp();
const query = `
query Page($slug: String!, $stage: Stage! = PUBLISHED) {
page(where: { slug: $slug }, stage: $stage) {
title
description
}
}
)
const variables = {
"stage": $preview ? "DRAFT" : "PUBLISHED",
"slug": "/about"
}
const { data: page } = await request(
HYGRAPH_ENDPOINT,
query,
variables
);
</script>
<template>
<h1>{{ page.title }}</h1>
<p>{{ page.description }}</p>
</template>

Nuxt preview URL structure

The preview URL you set up in the sidebar configuration of your schema would look like this:

https://yourwebsite.com/{slug}?preview=true

#Astro

Astro is generally focused on SSG rendering (static pages) and due to its incredible flexibility in terms of using frontend frameworks, there is no official “preview mode”.

To make it work with Hygraph:

  1. Use output: 'server' to render the Astro site in SSR mode
  2. Set an ENV variable for preview to true. For example: ASTRO_USE_PREVIEW and based on that set your stage from PUBLISHED to DRAFT.

As the site runs in SSR mode it will always query the DRAFT endpoint for fresh data.

In astro.config.mjs:

import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server',
adapter: vercel(),
});

In /src/pages/page.astro:

---
import { request } from "graphql-request";
const isPreview = import.meta.env.ASTRO_USE_PREVIEW === 'yes';
const query = `
query Page($slug: String!, $stage: Stage! = PUBLISHED) {
page(where: { slug: $slug }, stage: $stage) {
title
description
}
}
)`
const variables = {
"stage": $preview ? "DRAFT" : "PUBLISHED",
"slug": "/about"
}
const { data: page } = await request(
HYGRAPH_ENDPOINT,
query,
variables
);
---
<html>
<head>
<title>{page.title}</title>
</head>
<body>
<main>
<article>
<h1>{page.title}</h1>
<p>{page.description}</p>
</article>
</main>
</body>
</html>

Astro preview URL structure

Since you cannot set Astro to a preview mode like Next and Nuxt, what you will do is make it read from the DRAFT stage and set an ENV variable in the build system that says to query DRAFT. You should also configure the output: 'server' setting in the config.

You will then configure your preview URL in the sidebar by creating a URL for your web app that queries the DRAFT stage of your endpoint. This could look like this: https://preview.yourwebsite.com or it could have a query parameter in the URL like this: https://yourwebsite.com?preview=true.

Preview URL structure example:

https://preview.yourwebsite.com/{slug}