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.
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 see | What it means |
|---|---|
| Neither button | This content type has no URL configured, or the project has no site addresses set. Ask an admin to check Settings → Site URLs. |
| Only Preview draft | Normal for a draft. View live appears after you publish. |
| Only View live | The project has a live site address but no preview site address. An admin can add one. |
Is it safe to share a preview link?
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.
| Setting | Example | Used for |
|---|---|---|
| Live site | https://example.com | View live |
| Preview site | https://uat.example.com | Preview 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:
| Content | Tokens 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:
- Hold a preview API key (
preview_…) in server-side configuration. - Read
previewoff 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.
Related
- Public API usage
- API overview — authentication and key types

