Preview Mode

Show preview content in your website or application

Historically, a problem with API-first or headless content management systems has been a lack of in-place preview. That's because the content management system doesn't have any reference to preview the content - displaying it is the job of the site or application which consumes the content.

How we've resolved the preview issue in Rooftop

We've found a way to make preview work as you and your users expect. They get to see the content of their site or application, on the site or application.

Here's how it works:

  1. The user hits 'preview' on a post or page in Rooftop
  2. Their browser sends a POST request to a predefined endpoint on your site or application
    3. Your application retrieves the preview content from the Rooftop API and displays it in context

Sequence diagram of the preview process

Here's a sequence diagram to show the steps in the process:


Configuring Rooftop for preview mode

Preview Mode is an optional plugin, which you can turn on for your site under the Plugins menu.

Before using preview, you need to configure Rooftop with the endpoint where you want to receive the POST .


Ensuring only the right people see the preview content

Unpublished content might be sensitive, so it's important that only the person doing the previewing can see it. This is done by sharing a 'preview key' with the endpoint you configure. This preview key is also available when you hit the preview endpoint on the Rooftop API, so you can compare them.

How to access preview content

Every post or page has a preview endpoint, for example:

This will always show the latest revision of a post, even if it's in draft. The JSON structure is identical to the normal endpoint to retrieve a post or page:

except that it includes a preview key and value. This preview key is the one which was POSTed to your endpoint.


Make sure you add the include-drafts header to your request

The content being previewed might be in draft mode. You need to make sure you include a header with your API request called 'include-drafts', with a value of 'true'. See the reference page for draft mode.

Implementing preview in your site

Your site or application needs to do the following:

  1. Have a single endpoint to receive a POST request with the following parameters:
    • id: the ID of the post
    • post_type: the post type to preview (e.g. page)
    • preview_key: an MD5 hash of various parameters of the page. This changes each time the preview button is pressed.
  2. Retrieve the preview content and compare the preview keys - it's up to you to make sure this comparison happens
  3. Redirect to or render the post or page in the context of the site, showing the preview content.

Ruby / Rails client library reference implementation

We've written a reference implementation of the client-side aspect of preview mode into the rooftop-ruby and rooftop-rails gems.

The approach we take is as follows:

  1. the POST is received in the PreviewController -
  2. ensuring Rooftop.include_drafts is set to true, the controller requests the draft content and compares the preview keys
  3. If they match, an SHA of the preview key, and the key itself, is stored in the browser session.
  4. The route to the content is resolved from the post type (e.g. 'page') and ID, and the user is redirected to the right place on the site with the SHA appended as a querystring
  5. The controller on the site responsible for e.g. PagesController has the Rooftop::Rails::Preview mixin included, so can check for preview?() and return the preview content if true. preview?() does the job of checking the SHA on the querystring parameter matches the one in the session.


Why we SHA the preview key before redirecting to the real content

We could pass the preview key directly as a querystring parameter, and not have to mess about with the SHA. But in doing that, there's a chance that someone could share the URL to the preview page and it would work in another user's browser. Our implementation will only work in the browser which pressed 'preview'.