Preview is the last draft check#
Preview loads draft page content into your frontend without making it public. It is the safest place to confirm the page looks right before publishing.
A complete preview flow is:
Editor opens Visual Builder
-> CMS resolves the Website Preview URL with [pageId]
-> frontend fetches draft page by pageId
-> PageRenderer renders the draft
-> editor reviews or uses visual editing
-> editor publishes when readyPreview is deliberately separate from the public route. The public route uses the page slug and published delivery data.
Preview versus published delivery#
| Preview | Published delivery |
|---|---|
client.pages.getPreview(pageId) | client.pages.get() or getBySlug(path) |
| Draft content | Published content |
| Page ID | Public route path |
preview:read permission | delivery:read permission |
| Protected and no-store | Normal cache strategy |
| Editor review and visual editing | Customer-facing website |
Do not let a query parameter alone decide whether a visitor can see preview data. Your preview route must verify that the request is authorized.
Configure the preview URL#
In the CMS Website settings, set the Preview URL to a route template containing [pageId].
https://www.example.com/preview/page/[pageId]The admin replaces [pageId] and embeds that page in an iframe. If the placeholder is missing, the Visual Builder cannot identify the draft page to load.
Minimum preview implementation#
import { getContoprixPreviewPage } from "@contoprix/next/server";
import { VisualPreviewCanvas } from "@/contoprix/VisualPreviewCanvas";
export const dynamic = "force-dynamic";
export default async function PreviewPage({
params,
}: {
params: Promise<{ pageId: string }>;
}) {
const { pageId } = await params;
const page = await getContoprixPreviewPage({
pageId,
languageCode: "en",
});
return <VisualPreviewCanvas initialPage={page} />;
}Your server needs credentials that can call the preview API. Keep them outside the browser and make the response non-cacheable.
Preview checklist#
Review a page in the same conditions a visitor will see:
Content#
- The selected language is correct.
- Headings, rich text, and optional fields look intentional.
- Images have meaningful alt text and reasonable crops.
- Links use valid destinations and labels.
- Related entries are correct and ready to deliver.
Blocks and layout#
- Every expected block is visible.
- No missing-component placeholder appears.
- Components appear in the intended order.
- Blocks render in their expected regions.
- Header, footer, breadcrumbs, and navigation behave as intended.
- Empty optional fields do not create blank visual space.
Responsive and accessible behavior#
- Check at desktop and mobile widths.
- Test keyboard navigation and focus styles.
- Confirm headings have a sensible order.
- Check buttons and links have understandable text.
- Verify contrast and readable text over images.
Visual editing#
- Click a component block and confirm it selects.
- Edit a field, save the draft, and confirm the preview refreshes.
- Try inserting, moving, duplicating, and deleting a test block.
- Remember that content-entry and form fields are edited at their own source, not in the page block editor.
Test public delivery after publishing#
A preview can be perfect while the public site is still old or unavailable. After publishing:
- Open the normal public route, not the preview URL.
- Confirm the expected language is delivered.
- Confirm your cache revalidated.
- Verify the page in an unauthenticated browser session when it is public.
If preview is correct but the public page is wrong, the cause is usually one of these:
| Symptom | Check |
|---|---|
| Public page is old | The new draft was not published or the cache is stale. |
| Public page is 404 | The page/language lacks a published version or the route path is wrong. |
| A component is missing | The registry lacks the delivered component code. |
| Content has the wrong locale | The public route requested a different languageCode. |
| Preview does not refresh | The client lacks onRefresh or the preview route is cached. |
Preview security checklist#
- Preview credentials stay on the server.
- The preview route verifies editor authorization.
- Draft responses use no-store or dynamic rendering.
- Preview URLs do not become public share links.
- The parent admin origin is allow-listed for
postMessage. - A clear preview banner prevents confusion with the live site.
- Secrets never appear in browser logs, source code, or
NEXT_PUBLIC_variables.
Warning
Do not use preview as an alternative public page endpoint. It can expose unpublished content, content intended for later release, or incomplete localization.
Finish the workflow#
When the checklist passes, publish the page and verify delivery. Preview is where you gain confidence; publication is what changes the customer-facing website.