Setting up live preview with your frontend
Configure real-time visual live preview between SCHMA Studio and your Next.js or React application using @schmadev/preview and secure postMessage events.
Before you begin
- A frontend application using Next.js (App Router or Pages Router) or React
- The `@schmadev/preview` package installed in your frontend
- A preview secret configured in both SCHMA Studio and your environment variables
Visual Live Preview enables content editors to see real-time draft changes rendered inside your actual production frontend components as they type in the Studio, before anything is published.
How SCHMA visual preview works
When an editor opens Live Preview in the Studio, SCHMA loads your application's preview URL inside an embedded secure iframe. The Studio and your application establish a bidirectional postMessage channel. When editors change form fields, the Studio streams schma:preview-update events, and your page updates dynamically without requiring a page reload.
Installing the preview package
Install the lightweight @schmadev/preview package in your Next.js or React project:
npm install @schmadev/previewConfiguring Next.js Draft Mode route handler
In Next.js App Router, create an API route handler at app/api/preview/route.ts that validates a shared secret token and enables Next.js Draft Mode:
import { draftMode } from "next/headers";
import { redirect } from "next/navigation";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const secret = searchParams.get("secret");
const slug = searchParams.get("slug") || "/";
// Validate the secret token against your server environment
if (secret !== process.env.SCHMA_PREVIEW_SECRET) {
return new Response("Invalid preview token", { status: 401 });
}
// Enable Next.js Draft Mode cookies
const draft = await draftMode();
draft.enable();
// Redirect to the target content path
redirect(slug);
}Tagging elements with data-schma-field
Wrap your layout with <SchmaPreview> and add data-schma-field attributes to your rendered elements. This enables click-to-edit navigation: clicking an element in your preview iframe automatically focuses the corresponding input field in SCHMA Studio.
import { SchmaPreview } from "@schmadev/preview";
export function BlogPostPage({ post, isDraftMode }: { post: any; isDraftMode: boolean }) {
return (
<SchmaPreview enabled={isDraftMode} allowedOrigin="https://studio.schma.dev">
<article className="max-w-2xl mx-auto py-12">
<h1 data-schma-field="title" className="text-4xl font-bold">
{post.title}
</h1>
<div data-schma-field="body" className="prose mt-6">
{post.body}
</div>
</article>
</SchmaPreview>
);
}Security and iframe origin validation
The allowedOrigin prop ensures that <SchmaPreview> only responds to postMessage calls originating from your verified SCHMA Studio domain (e.g. https://studio.schma.dev). Messages from any other origin are strictly rejected, preventing clickjacking or unauthorized state mutations.