---
title: Staging and previews
status: current
order: 11
---

# Staging and previews

See a draft on your real site before you publish it. Works with any host: Netlify, Vercel, Cloudflare Pages, your own server.

The idea: **a second build of your site** (staging) that reads with a `preview` key, so it shows the latest version of everything, drafts included. Pluma rebuilds it every time something is saved, and every entry gets a **View on staging** link.

## 1. Build a staging site

Deploy the same site a second time, reading from Pluma with a **preview key** instead of the delivery key. With Netlify or Vercel that's usually a branch deploy or a second site with different environment variables:

| Variable | Live site | Staging site |
| --- | --- | --- |
| `PLUMA_SPACE` | your site | your site |
| `PLUMA_DELIVERY_KEY` | a `delivery` key (published only) | a `preview` key (latest, drafts included) |

The code doesn't change: a `preview` key answers the same [Delivery API](../api/delivery.md) with the latest version of each entry. See [Preview API](../api/preview.md).

Keep the staging site private (password or `noindex`): it shows unpublished content.

## 2. Tell Pluma where both sites live

In your site, **Settings → General**: the live site (`https://www.example.com`) and the staging site (`https://staging.example.com`). By API: `PATCH /api/v1/spaces/:space_id` with `production_url` and `preview_url`. By MCP: `update_site`.

## 3. Tell Pluma where each type lives

In each content type, **Page URL on your site**: `/blog/{slug}`, `/events/{slug}`, `/{slug}`. `{slug}` is the entry's slug field, `{id}` its id. By API or MCP it's the type's `url_path`.

With the URLs and the path, each entry gets:

- in the dashboard, **View on staging** and **View live** links;
- in the API and MCP, `sys.url` (live, only when published) and `sys.preview_url` (staging, only with a key that reads drafts). Your agent can hand you the exact link after a change.

## 4. A deploy hook for staging

In **Deploy → New deploy hook**, pick your host, paste the staging site's build hook and choose **The staging site**. A staging hook rebuilds on every save (`entry.saved`) as well as on publish, so a draft shows up there a minute later. Saves close together go out as a single build, 30 seconds after the last one.

By API: `POST /api/v1/spaces/:space_id/webhooks` with `"target": "preview"`. See [Webhooks](../api/webhooks.md).

Your live hook keeps rebuilding only when something is published: drafts never reach the live site.

## Is it set up?

When you save the site URLs (API `PATCH` or MCP `update_site`), the response includes `warnings` if something is missing: a staging URL without a staging hook, or no type with a `url_path` yet. The Deploy page shows the same warnings.
