Skip to content

Live Preview

The admin’s Live Preview button opens your frontend with a preview_token query parameter. The token is signed, scoped to one entry (or one page), and expires after 15 minutes. Without a valid token the normal public API still returns 404 for drafts.

In the CMS, set the templates under Settings → API:

  • Entry template: must contain {slug}, and may use {contentType}. For example https://your-site.com/blog/{slug}.
  • Page template: must contain {route}.
src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { createKenresoftClient, getPreviewToken } from '@kenresoft-cms/astro';
export const onRequest = defineMiddleware((context, next) => {
context.locals.cms = createKenresoftClient({
url: import.meta.env.PUBLIC_KENRESOFT_CMS_URL,
previewToken: getPreviewToken(context.url),
});
return next();
});
---
const post = await Astro.locals.cms.entries.get({ contentType: 'blog-post', slug });
---

entries.get() and pages.resolve() on that client use the token automatically. On a normal request getPreviewToken returns null and nothing changes. Pass previewToken: null on a call to force published-only rendering. An explicit previewToken on a call overrides the client default. Without middleware, pass the token per call: entries.get({ contentType, slug, previewToken: getPreviewToken(Astro.url) }).

The new-site starter includes this middleware.

  • The page must render on demand. Under output: 'static' with getStaticPaths(), a draft’s slug was never built, so Astro returns 404 before your code runs. Use output: 'server', or add export const prerender = false; to just that page (needs an adapter).
  • Save first. Live Preview shows the saved entry, not unsaved edits.
  • Pages: a preview link goes to a route that is not in the published pages.list(). Check for a token first and call pages.resolve({ route }) directly, as the example site’s catch-all does. See Rendering pages.
  • Commerce product pages have no preview token: products are not entries.

If a draft still returns 404 on an on-demand page, check the token has not expired (15 minutes), that the URL matches the button’s exactly, and that the request actually reaches the client you think it does.