Tue Nov 08 2022
Implementing Sanity.io preview in a SvelteKit project
This article is a complete guide to implementing document preview in Sanity Studio targeting a SvelteKit site. We'll take a look at the setup for Sanity in brief, and we will focus mainly on the SvelteKit part, since there are plenty of resources for the Sanity config.

Before we get started, note that this approach will only work for server rendered SvelteKit sites. It will not work for statically generated sites.
The main idea is to have Sanity Studio point to an api endpoint in the SvelteKit site. This api endpoint will then setup preview for the site and redirect to the correct page, which will then display any available preview data. Preview data in a Sanity context is draft documents.
There are two main parts, the Sanity Studio preview setup and the Setup for the SvelteKit site. Let's get to it!
Sanity Studio preview setup
Here I'll assume that you have already a running Sanity Studio instance ready to go.
First, install the Production Preview plugin and follow the docs to get set up. Url: https://www.sanity.io/docs/preview-content-on-site.
Note that you might prefer to use an iframe plugin to handle preview instead, especially if you want to add preview for only some documents. See this link for more info: https://www.sanity.io/plugins/iframe-pane
The resolveProductionUrl.js|ts
file you created when installing the Preview Plugin will probably need some tweaking.
We will be passing information to the SelteKit site using searchParams/queryParams.
It's usually a good idea to pass a secret key (you can use https://randomkeygen.com to generate one) which will be used in the SvelteKit site to validate that the request is coming from Sanity Studio. This prevents outsiders from calling the preview api route in the SvelteKit site).
When it comes to which params to send to the SvelteKit site, that depends on the structure of you site. You'll need to pass enough info to be able to construct the paths on the SvelteKit site.
For this site, we have pages and blog posts. The pages have slugs that render on the root of the site (like /about). The blog posts are grouped by date and slug. So for this site the resolveProductionUrl.ts
will look something like this:
The resolveProductionUrl
will now return the correct url and and search params to our SvelteKit site. It will look something like this (for localhost): http://localhost:5173/api/preview?_type="page"&slug="aboutPage"&secret=my-secret
Moving on to the SvelteKit site where we'll use the params from this url eventually.
SvelteKit site preview setup
Again, we will assume that you have a SvelteKit project setup and working. We will also assume that you are using Typescript, but this is not required.
There are several parts to handling preview in the SvelteKit project.
- Writing groq queries that returns both drafts and published documents
- Handling previews in your Sanity data fetching methods
- Filtering documents based on whether preview is active
- Using the preview param in pages
- Creating an api route to handle the request from Sanity
- Setting up a hook to inform pages about the preview status
We'll start with the pages and work our way to handling the url we just created in the Sanity setup.
Setting up preview for your pages
[If you are using Typescript] First go into the `src/app.d.ts` and change `Locals` to the following:
This will add proper typing when using locals in pages.
Speaking of pages, open one of the (server) pages where you need to implement preview. In my case I want to have preview enabled for the about page (src/routes/about/+page.server.ts). First we import locals
and extract the preview param from it. For now, locals.preview
will always be undefined. We'll fix that later with a hook.
Note that the steps taken for the about page in this example needs to be repeated for all pages that should support preview.
The getAboutPageData
function takes preview
as a parameter. This will let the function know whether to return a published page, or a draft (if it exists). This is how this function might look (please read the comments):
The api route and the hook/middleware
Back in the Sanity setup we implemented the resolveProductionUrl
function. This function returned a url which was something like http://localhost:5173/api/preview?_type="page"&slug="aboutPage"&secret=""...
.
Now we need to create the /api/preview
endpont in our SelteKit app and have it redirect to the correct page. Let's start by creating a new endpoint at src/routes/api/preview/+server.ts
.
To summarize. This endpint take in all search parameters from Sanity, validates the key and builds a path to the correct url (in this case the about page). It also sets a cookie as a flag that preview is
The last step is the hook. If you haven't used server hooks in SvelteKit, take a look at the docs here: https://kit.svelte.dev/docs/hooks#server-hooks
Remember back when we defined the server route for the about page(src/routes/about/+page.server.ts)? We used the locals.preview
in that route? Now we are going to set the value for locals.preview
using a server hook.
That's it. Now preview will work for any pages you have configured.
Side note. Exiting preview.
If you open a page in preview mode in Sanity you will be "stuck" in preview mode until you close the browser. The preview cookie is true for the duration of the session. It might be a good idea to provide an escape hatch allowing any Sanity editors to exit preview mode without having to close the browser. A simple way of doing this is to provide a link to a route that removes the preview cookie. An example of such a route can be found below.