🎈 Welcome to the Marketplace — Explore and discover the ecosystem around DatoCMS, and share your own work with the community!

Web Previews

Offer your editors side-by-side previews of unpublished/draft content, directly within DatoCMS

This is a Community Plugin! Learn how create your own plugin, or copy and remix existing ones in our documentation

Web Previews DatoCMS plugin

This plugin adds side-by-side previews, and quick links in the record sidebar to preview your webpages.

🚨 Important: This is not a drag & drop plugin! It requires a lambda function on your frontend website(s) in order to function. Read more in the following sections!

Installation and configuration

Once the plugin is installed you need to specify:

  • A list of frontends. Each frontend specifies a name and a preview webhook, which will be called as soon as the plugin is loaded. Read more about it on the next chapter.
  • Sidebar open: to specify whether you want the sidebar panel to be opened by default.

⚠️ For side-by-side previews to work, if your website implements a Content Security Policy frame-ancestors directive, you need to add https://plugins-cdn.datocms.com to your list of allowed sources, ie.:

Content-Security-Policy: frame-ancestors 'self' https://plugins-cdn.datocms.com;

The Previews webhook

Each frontend must implement a CORS-ready JSON endpoint that, given a specific DatoCMS record, returns an array of preview link(s).

The plugin performs a POST request to the Previews webhook URL, passing a payload that includes the current environment, record and model:

{
"item": {},
"itemType": {},
"currentUser": {},
"environmentId": "main",
"locale": "en",
}
  • item: CMA entity of the current record
  • itemType: CMA entity of the model of the current record
  • currentUser: CMA entity of the collaborator, SSO user or account owner currently logged in
  • environmentId: the current environment ID
  • locale: the locale currently active on the form

The endpoint is expected to return a 200 response, with the following JSON structure:

{
"previewLinks": [
{
"label": "Published (en)",
"url": "https://mysite.com/blog/my-article"
},
{
"label": "Draft (en)",
"url": "https://mysite.com/api/preview/start?slug=/blog/my-article"
}
]
}

The plugin will display all the returned preview links.

Implementation examples

If you have built alternative endpoint implementations for other frameworks/SSGs, please open up a PR to this plugin and share it with the community!

Next.js

We suggest you look at the code of our official Next.js demo:

Nuxt 3

Below here, you'll find a similar example, adapted for Nuxt. For the purpose of this example, let's say we want to return a link to the webpage that contains the published content.

If you deploy on a provider that supports edge functions, Nuxt 3 applications can expose a dynamic API: files in the /server/api folders will be converted into endpoints. So it's possible for DatoCMS to make a POST request to the Nuxt app with the info about the current record. What we'll actually do, is to implement a CORS enabled API endpoint returning an array of preview links built on the base of the record, the item type and so on:

// Put this code in the /server/api directory of your Nuxt website (`/server/api/preview-links.ts` will work):
// this function knows how to convert a DatoCMS record into a canonical URL within the website.
// this function knows how to convert a DatoCMS record
// into a canonical URL within the website
const generatePreviewUrl = ({ item, itemType, locale }) => {
switch (itemType.attributes.api_key) {
case 'landing_page':
return `/landing-pages/${item.attributes.slug}`;
case 'blog_post':
// blog posts are localized:
const localePrefix = locale === 'en' ? '' : `/${locale}`;
return `${localePrefix}/blog/${item.attributes.slug[locale]}`;
default:
return null;
}
};
export default eventHandler(async (event) => {
// In this method, we'll make good use of the utility methods that
// H3 make available: they all take the `event` as first parameter.
// For more info, see: https://github.com/unjs/h3#utilities
// Setup content-type and CORS permissions.
setResponseHeaders(event, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type, Authorization', // add any other headers you need
})
// This will allow OPTIONS request
if (event.req.method === 'OPTIONS') {
return send(event, 'ok')
}
// Actually generate the URL using the info that DatoCMS is sending.
const url = generatePreviewUrl(await readBody(event))
// No URL? No problem: let's send back no link.
if (!url) {
return { previewLinks: [] }
}
// Let's guess the base URL using environment variables:
// if you're not working with Vercel or Netlify,
// ask for instructions to the provider you're deploying to.
const baseUrl = process.env.VERCEL_BRANCH_URL
? // Vercel auto-populates this environment variable
`https://${process.env.VERCEL_BRANCH_URL}`
: // Netlify auto-populates this environment variable
process.env.URL
// Here is the list of links we're returnig to DatoCMS and that
// will be made available in the sidebar of the record editing page.
const previewLinks = [
// Public URL:
{
label: 'Published version',
url: `${baseUrl}${url}`,
},
]
return { previewLinks }
})

SvelteKit 2

Below here, you'll find a similar example, adapted for SvelteKit. For the purpose of this example, let's say we want to return a link to the webpage that contains the published content.

Create a +server.ts file under src/routes/api/preview-links/ with following contents:

import { json } from '@sveltejs/kit';
const generatePreviewUrl = ({ item, itemType, locale }: any) => {
switch (itemType.attributes.api_key) {
case 'landing_page':
return `/landing-pages/${item.attributes.slug}`;
case 'blog_post':
// blog posts are localized:
const localePrefix = locale === 'en' ? '' : `/${locale}`;
return `${localePrefix}/blog/${item.attributes.slug[locale]}`;
case 'post':
return `posts/${item.attributes.slug}`;
default:
return null;
}
};
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Content-Type': 'application/json'
};
export async function OPTIONS() {
setHeaders(corsHeaders);
return json('ok');
}
export async function POST({ request, setHeaders }) {
setHeaders(corsHeaders);
const data = await request.json();
const url = generatePreviewUrl(data);
if (!url) {
return json({ previewLinks: [] });
}
const baseUrl = process.env.VERCEL_BRANCH_URL
? // Vercel auto-populates this environment variable
`https://${process.env.VERCEL_BRANCH_URL}`
: // Netlify auto-populates this environment variable
process.env.URL;
const previewLinks = [
// Public URL:
{
label: 'Published version',
url: `${baseUrl}${url}`
}
];
return json({ previewLinks });
}
Web Previews
Offer your editors side-by-side previews of unpublished…
Publisher
Author gravatarstefanoverna
Package
Visit NPM
Current version
1.0.16
Installs count
Last update