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.

Content Management7 min read·Updated October 2026

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:

Terminal
npm install @schmadev/preview

Configuring 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:

app/api/preview/route.ts
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.

components/BlogPostPreview.tsx
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.