Enable instant content preview for your headless Umbraco setup. One-click preview from Umbraco backoffice, works with Next.js, Nuxt, Astro, and more.
$ dotnet add package DoubleShore.Umbraco.HeadlessPreviewInstant frontend preview for your headless Umbraco setup
Built with ❤️ by Double Shore - Your trusted Umbraco specialists.
DoubleShore.Umbraco.HeadlessPreview seamlessly connects Umbraco's backoffice to your frontend application, enabling content editors to preview unpublished changes in real-time with a single click.
When you decouple Umbraco from your frontend, you lose the native preview functionality. This package brings it back - better than ever.
| Feature | Description |
|---|---|
| One-Click Preview | Preview button appears directly in Umbraco's content editor |
| Any Frontend | Works with Next.js, Nuxt, Astro, SvelteKit, Remix, and more |
| Multi-Language | Full support for multilingual content preview with localized labels |
| Draft Mode |
| Integrates with your frontend's draft/preview mode |
| Localization | Preview label can be localized via Umbraco dictionary |
| Zero Config | Just add your frontend URL - we handle the rest |
| Lightweight | Minimal footprint, maximum performance |
dotnet add package DoubleShore.Umbraco.HeadlessPreviewOr via NuGet Package Manager:
Install-Package DoubleShore.Umbraco.HeadlessPreview
Add to your appsettings.json:
{
"HeadlessPreview": {
"BaseUrl": "https://your-frontend.com",
"PreviewSecret": "your-super-secret-key",
"PreviewEndpoint": "/api/preview",
"PreviewLabel": "Preview on Frontend",
"UseLocalization": true
}
}Create a preview API endpoint on your frontend. See examples below for each framework.
Click "Preview on Frontend" in Umbraco's content editor to see your unpublished changes.
To localize the preview label:
HeadlessPreview_LabelPreviewLabel to #HeadlessPreview_Label in appsettings.json{
"HeadlessPreview": {
"PreviewLabel": "#HeadlessPreview_Label",
"UseLocalization": true
}
}| Setting | Description | Default |
|---|---|---|
BaseUrl | Your frontend URL | required |
PreviewSecret | Shared secret for authentication | required |
PreviewEndpoint | Path to your preview API | /api/preview |
PreviewLabel | Button label (or dictionary key with #) | Preview on Frontend |
UseLocalization | Enable dictionary lookup for label | true |
Enabled | Enable/disable the package | true |
// 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 path = searchParams.get('path');
if (secret !== process.env.PREVIEW_SECRET) {
return new Response('Invalid token', { status: 401 });
}
const draft = await draftMode();
draft.enable();
redirect(path || '/');
}// server/api/preview.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event);
if (query.secret !== process.env.PREVIEW_SECRET) {
throw createError({ statusCode: 401, message: 'Invalid token' });
}
// Enable preview mode via cookie
setCookie(event, 'preview-mode', 'true', { path: '/' });
return sendRedirect(event, query.path as string || '/');
});// src/pages/api/preview.ts
import type { APIRoute } from 'astro';
export const GET: APIRoute = async ({ request, cookies, redirect }) => {
const url = new URL(request.url);
const secret = url.searchParams.get('secret');
const path = url.searchParams.get('path');
if (secret !== import.meta.env.PREVIEW_SECRET) {
return new Response('Invalid token', { status: 401 });
}
cookies.set('preview-mode', 'true', { path: '/' });
return redirect(path || '/');
};Contributions are welcome! Please feel free to submit a Pull Request.
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
Double Shore is a digital consultancy specializing in Umbraco development, headless CMS architectures, and modern web solutions.