# Set up live preview

Configure live preview in Hygraph so editors can see draft content rendered in your frontend before publishing.

Live preview loads your frontend in a side-by-side iframe inside Studio. Editors open any entry, click **Open live preview**, and see exactly how their unpublished changes look on the actual site, without leaving the entry form.

The preview refreshes when the editor saves the content entry. It does not update in real time as the editor types. Live preview is not compatible with native mobile applications. Requests made by the preview count against your project's rate limits.

**Note:**
Live preview does not require the Hygraph Preview SDK. Configure your frontend to serve DRAFT content first, then add the Preview widget in Studio with that URL template.

## Create a draft preview token

Your preview URL needs to serve content from Hygraph's `DRAFT` stage. Create a Permanent Auth Token with `DRAFT` as the default stage for preview, and a second token with `PUBLISHED` as the default stage for production. Your application switches between them based on context.

1. Go to **Project Settings > Access > Permanent Auth Tokens**.
2. Click **Add token** and give it a name, for example, `Preview token`.
3. Under **Default stage for content delivery**, click **Change default stage**, and select **Draft**.
4. Click **Initialize defaults**.

Repeat the above steps to create a production token: name it, for example, `Production token`, set the default stage to **Published**, and click **Initialize defaults**. Use this token for live traffic so visitors only receive published content; use the draft preview token only when the preview URL is loaded.

## Choose a preview URL

[Implement your frontend](https://hygraph.com/docs/developer-guides/schema/live-preview-frontend) so it serves `DRAFT` content for the template you will paste into Studio. Pick the row that matches your frontend and use its URL template in the Preview widget:

| Frameworks | How it works | URL template |
|---|---|---|
| React, Vue, Nuxt, Vanilla JavaScript | The frontend reads `?preview=true` and switches the GraphQL stage for that request. | `https://your-domain.com/{slug}?preview=true` |
| Next.js | Studio hits a preview route that validates a secret, sets a cookie or session, and redirects to the content page. The content page then queries `DRAFT`. | `https://your-domain.com/api/preview?secret=MY_SECRET_TOKEN&slug={slug}` |
| Remix | Studio hits a preview route that validates a secret, sets a cookie or session, and redirects to the content page. The content page then queries `DRAFT`. | `https://your-domain.com/preview?secret=MY_SECRET_TOKEN&slug={slug}` |
| Astro | A separate host or environment always serves `DRAFT`. The URL points at the content page directly. | `https://preview.your-domain.com/{slug}` |

## Add a preview widget

You need to configure the Preview widget once per content model. Use the URL template from [Choose a preview URL](#choose-a-preview-url) that matches your frontend.

[Video: Add a preview widget](https://eu-central-1-shared-euc1-02.graphassets.com/AvHQ3RDvFSousA8iwElOKz/cmovea1goibsv06w2xaowrhbd)

1. In your Hygraph project, click **Schema**.
2. Select the model you want to enable preview for.
3. Click the **Sidebar** tab at the top of the screen.
4. Select the **Preview** widget from the right sidebar.
5. Complete the **Preview name** and **URL template** fields. Paste the template from your frontend setup. See [Define a preview URL template](#define-a-preview-url-template) for how placeholders such as `{slug}` work.
6. Click **Add**.

If more than one preview URL is required, for example, a local development URL and a staging URL, click **+ Add** to add additional URLs. Editors select between them using a dropdown in the content entry sidebar.

### Define a preview URL template

The URL template tells Studio how to construct the preview link for each entry. It uses your domain plus one or more field values from the content entry as identifiers.

Use curly brace notation to insert field values. As soon as you type `{` in the **URL template** field, Studio shows two groups of available tokens:

**Available fields**: These are the fields on your model. Default system fields available on every model are `id`, `createdAt`, `updatedAt`, `publishedAt`, and `scheduledIn`. Any custom fields you have added to the model, such as `slug`, also appear here.

**Other placeholders**: `{locale}` adds a locale selector to the preview. When your model has more than one locale configured, editors can switch between locales directly in the preview panel. Without it, the switcher does not appear even if your project has multiple locales configured.

**Common patterns:**

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

Use `{slug}` when your frontend routes by slug. Use `{id}` when it routes by entry ID. You can combine multiple fields and placeholders in a single template if your URL structure requires it.

Framework-specific templates, including redirect routes with a secret token, are listed in [Choose a preview URL](#choose-a-preview-url). Implementation code for each framework is in [Frontend implementation](https://hygraph.com/docs/developer-guides/schema/live-preview-frontend).

**Warning:**
If your preview URL serves the PUBLISHED stage, editors will see changes in the preview only after they publish the content entry. The preview will not show any draft content. See [Create a draft preview token](#create-a-draft-preview-token) and [Choose a preview URL](#choose-a-preview-url).

#### Add a secret token

For Next.js and Remix, include a secret in the URL that only your application and Hygraph know. This prevents the preview route, for example `https://your-domain.com/api/preview?secret=MY_SECRET_TOKEN&slug={slug}`, from being accessed directly without going through Studio. React, Vue, Nuxt, Vanilla JavaScript, and Astro URL templates do not require this secret.

**Warning:**
React, Vue, Nuxt, and Vanilla JavaScript templates use `?preview=true` (or similar) with no secret. Anyone who discovers that URL pattern can view unpublished draft content. For sensitive content, add a secret check like the Next.js and Remix examples, or restrict access to your preview deployment.

Astro uses a separate preview deployment that always serves drafts. Keep that deployment access-restricted (for example behind authentication or your hosting provider's protection).

1. Generate a secret key using a key generator of your choice. Use a strong random string.
2. Replace `MY_SECRET_TOKEN` in the URL template with the generated secret.
3. Add the secret to your app environment as `HYGRAPH_PREVIEW_SECRET` (for example in `.env.local` for Next.js):

    ```bash
    HYGRAPH_PREVIEW_SECRET=MY_SECRET_TOKEN
    ```

Next.js and Remix use a secure cookie or session for preview. For local development over `http://localhost`, you may need to temporarily allow insecure cookies or test against an HTTPS preview URL so the cookie works inside the Studio iframe.

### Add a Variants preview URL

If your model uses [Variants](https://hygraph.com/docs/developer-guides/schema/variants), you can add one of the variant placeholders, such as `${variant.id}`, `{variant.segments[0].id}`, or `{variant.segments[*].id}`, to your URL template. This lets Studio construct a preview URL that passes the variant or segment ID to your frontend. Editors can preview how content looks for a specific segment before publishing. Without a variant placeholder in the URL template, the variant or segment ID is not passed to the frontend and the preview shows the main entry content only.

You can combine variant placeholders with `{locale}` in the same URL template. Use `{id}` for the entry ID, the same as in a standard preview URL. `${variant.id}` uses a `$` prefix; segment placeholders use curly braces only.

[Video: Live preview for Variants](https://eu-central-1-shared-euc1-02.graphassets.com/AvHQ3RDvFSousA8iwElOKz/cmovgxicbs2bn06w2jpxecr70)

Ensure you have [added the Preview widget and defined a base URL template](#add-a-preview-widget) before configuring Variants preview.

1. In your Hygraph project, click **Schema** and select the model.
2. Click the **Sidebar** tab.
3. Click **Edit widget** on the Preview widget.
4. Under **Variant preview settings**, complete the **Preview name** and **URL template** fields.
5. Click **Update**.

**Supported URL template tokens for Variants:**

| Token                      | Resolves to                                      |
|----------------------------|--------------------------------------------------|
| `${variant.id}`            | The variant ID                                   |
| `{variant.segments[0].id}` | The first segment ID                             |
| `{variant.segments[*].id}` | All segment IDs, comma-separated and URL-encoded |

**Example URLs and what they resolve to:**

| Approach         | Template                                                                       | Example output                                               |
|------------------|--------------------------------------------------------------------------------|--------------------------------------------------------------|
| By variant ID    | `https://preview.your-domain.com/post/{id}?variant=${variant.id}`              | `.../post/cmeaacg1t...?variant=cmeaacld1...`                 |
| By first segment | `https://preview.your-domain.com/post/{id}?segment={variant.segments[0].id}`   | `.../post/cmeaacg1t...?segment=cmeaafql4...`                 |
| By all segments  | `https://preview.your-domain.com/post/{id}?segments={variant.segments[*].id}`  | `.../post/cmeaacg1t...?segments=cmeaafql4...%2Ccmeaafn9e...` |

`{variant.segments[*].id}` returns all segment IDs as a comma-separated list. Commas are URL-encoded as `%2C`. Your frontend interprets the query parameter and queries the API for the correct variant.

## Verify the setup

1. Open an entry in Studio for the model you configured live preview.
2. In the right sidebar, click **Open live preview**. The preview should load alongside the entry form.
3. Make a change to a field and click **Save & Preview**. The preview should refresh and show your change.

If the preview panel is blank or shows an error, see the [Troubleshooting](#troubleshooting) section.

## Edit or delete a preview URL

1. Navigate to the **Schema** builder and select the model.
2. Next to the **Preview** widget, do one of the following:
    - To edit a preview URL, click the pencil icon, update the **Preview name** or **URL template** fields, and click **Update**.
    - To delete a preview URL, click the trash icon at the end of the row you want to remove.

A preview widget needs to contain at least one URL. If you need to remove the only configured URL, delete the widget from the **Sidebar** tab instead. You can re-add the widget later if needed.

**Delete the preview widget**

![Delete a preview widget](https://hygraph.com/images/docs/user-guides/live-preview/remove-preview-widget.png)

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`.

## Troubleshooting

### CSP or security header issues

Your site's security headers are blocking iframe embedding. Check your response headers in your browser's developer tools:
1. Navigate to the **Network** tab.
2. Search for the page you are trying to see.
3. Under the **Headers** subtab, click the **Response Headers**.
4. Determine whether the security configuration matches one of the options below:
    - If `X-Frame-Options` is set, remove it from your application.
    - If `Content-Security-Policy` is set, add `frame-ancestors 'self' https://*.hygraph.com` to the header value.

If you are hosting on Vercel, go to **Settings > Deployment Protection** and disable **Vercel Authentication**. This removes the `X-Frame-Options` header. Disabling Vercel Authentication makes preview deployments publicly accessible.

### Stale data

Your frontend is serving the `PUBLISHED` stage in preview. Check that:

- Your preview token has `DRAFT` set as the default content stage.
- Your application is using the preview token, not the production token, when the preview URL is loaded.
- Your GraphQL queries are not hardcoding `stage: PUBLISHED`.
- You do not have a caching layer active in preview mode.

### No Open live preview button

The entry should have been saved at least once, that is, it should exist in the `DRAFT` stage. The button does not appear on unsaved entries.

## What's next

- [Click to Edit setup](https://hygraph.com/docs/developer-guides/schema/click-to-edit): Learn how to install the Hygraph Preview SDK and configure Click to Edit so editors can jump from any preview element directly to the corresponding field in Hygraph Studio.
