TentoCMS
Guides

Previewing content

This guide has two halves. The first is for editors — how to look at a draft as a real page. The second is for whoever builds the website, because the preview button only works once the site has been wired up for it.

This guide has two halves. The first is for editors — how to look at a draft as a real page. The second is for whoever builds the website, because the preview button only works once the site has been wired up for it.


For editors

Open any page, blog post or collection item. If preview is set up for that kind of content, two buttons sit at the top of the editor:

  • Preview draft — opens your unsaved-to-the-world changes on the preview site, in a new tab.
  • View live — opens the published version on the real site. It only appears once the content has been published, because before that there is nothing live to look at.

That is the whole workflow. There is no key to copy, no URL to assemble, and nothing to type.

Why don't I see the buttons?

What you seeWhat it means
Neither buttonThis content type has no URL configured, or the project has no site addresses set. Ask an admin to check Settings → Site URLs.
Only Preview draftNormal for a draft. View live appears after you publish.
Only View liveThe project has a live site address but no preview site address. An admin can add one.

Yes, with the caveat that it only works for people who can already reach your preview environment. The link itself carries no password or key — it is just an address. Anyone who can open your preview site can see the draft; anyone who cannot, cannot.


For developers: wiring up preview

TentoCMS does not render your pages, so it cannot preview them on its own. It builds an address and your site does the rest.

1. Configure the addresses in TentoCMS

Everything lives on one screen: Settings → Site URLs, available to developers and above.

It sets two origins, which are admin-only because they decide where the live and preview sites actually are. Developers can see them — so they can tell what their paths resolve to — but not change them.

SettingExampleUsed for
Live sitehttps://example.comView live
Preview sitehttps://uat.example.comPreview draft

Below that, every content type gets a URL pattern describing where its content lives — blog posts, each page type and each collection type, all in one list, all editable by a developer:

Page and collection patterns can also be edited on the individual type editors (Settings → Page types / Collection types), which write the same value — the Site URLs screen is the place to see them all at once.

A pattern is a root-relative path with {slug} where the item's slug goes:

/blog/{slug}
/guides/{slug}
/{pageTypeSlug}/{slug}

Tokens are specific to the kind of content, because only some values exist in each case. A pattern using a token its content type cannot supply is rejected when you save it:

ContentTokens available
Page types{slug}, {pageTypeSlug}
Collection types{slug}, {collectionSlug}
Blog posts{slug}

A pattern must contain {slug} unless the type is a singleton collection, which holds one item and can therefore use a fixed path like /privacy-policy. Leave the pattern empty for a type that is not a page on your site — the buttons then correctly do not appear.

Patterns are paths only: no scheme, no host, and no query string or fragment. A query would be carried into the generated link, so /blog/{slug}?preview=true would make the live link ask for draft content.

2. Forward ?preview=true on your preview environment

The preview button produces:

https://uat.example.com/blog/my-post?preview=true

?preview=true means nothing to your site until you act on it. Your preview deployment must:

  1. Hold a preview API key (preview_…) in server-side configuration.
  2. Read preview off the incoming request and pass it through to its TentoCMS API calls.
// Server-side only. Sketch — adapt to your framework.
const wantsDraft = new URL(request.url).searchParams.get('preview') === 'true'

const res = await fetch(
  `https://api.tentocms.com/api/v1/blog/posts/${slug}${wantsDraft ? '?preview=true' : ''}`,
  { headers: { 'X-API-Key': process.env.TENTO_PREVIEW_KEY! } }
)

Holding a preview key is not the same as asking for drafts. A request authenticating with a preview key and no ?preview=true still receives published content, so one deployment serves both modes — you do not need a separate build to preview.

⚠️ Never do this on your production site

Do not wire the ?preview=true passthrough into your public production deployment. If you do, any visitor can append ?preview=true and read unpublished content. This is why TentoCMS keeps the preview address as a separate setting rather than a flag on the live one, and why preview links always point at the preview environment.

The preview environment must not be publicly reachable. Put it behind authentication, an IP allowlist, or a private network — the same protection you would give any staging environment.

Note on caching

A request authenticating with a preview key skips the edge cache entirely, including for published content. That is deliberate, and it means your preview environment's response times will not reflect production. Benchmark against the live site, not the preview one.


Copyright © 2026