Who this is for. Developers adding preview to a site or to a headless front end, and authors who want to see a version before it goes live. After this page you can preview any saved revision, and build a preview that does not leak unpublished content.
Previewing a saved revision
Add ?revision=<id> to the record's normal URL, for example /about-us?revision=3424. The platform honours it only when the request comes from a signed-in backend user: for anyone else, an anonymous visitor or a signed-in member, the published, active content renders as it would without the parameter. A preview link that reaches the wrong person shows them only what is already public.
When the parameter is honoured:
- the revision is looked up by its id, and an id that is not found answers 404;
- if the revision has a layout, that layout's template renders it, so a version saved on another layout previews as it will look;
- the revision stands in as the active revision for this one request; nothing is saved, and the record's active revision does not change;
- the response is never stored in the page cache, so a preview cannot be served to the next visitor.
With "Show unpublished" on, the default for backend users, the same URL also works for a record that is not published yet. There is nothing to write in a template: the platform handles the parameter before the template runs, and every layout area getter then reads the revision you asked for.
Book pages
Book pages have a preview route of their own, keyed on the book, unit and page slugs and the revision id, with the same rule: a revision that is not active answers 404 unless the request comes from a signed-in backend user.
Live preview is a different mechanism
Live preview renders the edit form's unsaved content while an author types. It is a PUT request with submitIntent=livePreview, open to backend users only, and has nothing to do with ?revision=. What it does to template output is on The shorthand and live preview.
Previewing from a headless front end
A headless front end renders content it reads through the API, and its visitors have no admin session, so ?revision= on the Core dna URL does not help it. To show content that is not live, the front end asks for it explicitly, authenticated as a backend user:
- add
?retrieveUnpublished=1to a listing to include unpublished records, or read one record by its id; - to show a saved version that is not active yet, render the record's
lastRevisioninstead of itsactiveRevision, remembering that it is the newest revision of any kind, a draft included (Versioned content and the live revision shows both in a response).
Both reads are gated exactly as the published filter is (see Published, active and draft: the two gates): only a backend user's credential gets them. That credential, an OAuth access token by preference or an API key as the older option, belongs to the integration and stays on its server. The browser asks your server for a preview, your server checks that the person may see it, and only then makes the API call; the credential never reaches the browser.