Preview tokens
A preview token lets your site render the latest draft of an Object without putting a write key in the browser. The Cosmic dashboard issues the token when an editor clicks Preview. Your site passes it to the API with the Bucket read key.
How it works
- An editor clicks Preview on an Object in the dashboard.
- The dashboard calls Cosmic and receives a JWT plus a preview URL.
- The site loads in a split pane (or a new tab). The URL includes
preview_token. - Your server reads the token (query string or
cosmic_previewcookie) and fetches Objects withpreview_tokenandstatus=any. - The token is bound to one Bucket and expires after one hour. Click Preview again to get a new one.
The dashboard session never goes to the public API. The Bucket read_key stays on your server. The preview token only unlocks draft reads.
Query parameter
Add preview_token on Object list, Object get, and revision reads:
GET https://api.cosmicjs.com/v3/buckets/:slug/objects?read_key=READ_KEY&preview_token=TOKEN&status=any
Rules:
- Missing token: unchanged. Published by default.
status=anystill works with the read key alone. - Valid token: treated as
status=anyeven if you omitstatus. Must match the Bucket (bidclaim). - Invalid or expired token:
401. Fall back to published content.
Do not store the token on the Object type preview link. Tokens expire. The dashboard appends a fresh token each time.
SDK
import { createBucketClient } from '@cosmicjs/sdk'
const cosmic = createBucketClient({
bucketSlug: process.env.COSMIC_BUCKET_SLUG,
readKey: process.env.COSMIC_READ_KEY,
previewToken, // optional, from the URL or cosmic_preview cookie
})
const { object } = await cosmic.objects
.findOne({ type: 'posts', slug: 'hello-world' })
.status('any')
.props(['title', 'slug', 'metadata'])
Only pass previewToken on the server. Never put it in a client component.
Next.js helper
Sites built with Cosmic Autopilot or an agent get this injected. For an existing Next.js app:
// lib/cosmic-preview.ts
import { cookies } from 'next/headers'
import { createBucketClient } from '@cosmicjs/sdk'
export async function getCosmic(previewToken?: string) {
const token =
previewToken || (await cookies()).get('cosmic_preview')?.value
const cosmic = createBucketClient({
bucketSlug: process.env.COSMIC_BUCKET_SLUG as string,
readKey: process.env.COSMIC_READ_KEY as string,
...(token ? { previewToken: token } : {}),
})
return { cosmic, previewToken: token }
}
Set an httpOnly cookie when preview_token is on the query string. Use SameSite=None; Secure so the cookie works inside the dashboard iframe on app.cosmicjs.com. Preview only works over HTTPS.
Allow the dashboard to frame the site. Include localhost so Preview works when the dashboard is running locally. Set this on next.config headers (Vercel), not only middleware. Do not send X-Frame-Options: DENY.
Content-Security-Policy: frame-ancestors 'self' http://localhost:3040 http://localhost:3000 https://app.cosmicjs.com https://*.cosmicjs.com
If the site blocks iframes, the dashboard still offers Open in new tab.
Preview link template
Set a preview link on the Object type (Bucket > Object type > Additional settings), or let an Autopilot / agent deploy set it to:
https://your-site.com/api/cosmic-preview?object_id=[object_id]
Placeholders: [object_id], [object_slug], [revision_id], [timestamp]. The dashboard adds preview_token when Preview is clicked.
See dashboard Buckets for the editor workflow.