Add a headless CMS with Live Preview to SvelteKit in 5 Minutes
Storyblok is the first headless CMS that works for developers & marketers alike.
This short tutorial will show you how to integrate the Storyblok API into a SvelteKit app. We will also enable the real-time editing experience in the Visual Editor with the Storyblok JS Bridge - so that you can see your changes right away. At the end of this article, you will have a SvelteKit application that renders components filled with data from Storyblok.
If you don't know what a Headless CMS is or what Storyblok does, please read first the Storyblok Guide.
If you’re in a hurry, try the live demo in Stackblitz!
Environment Setup
Requirements
To follow this tutorial, make sure to meet these requirements:
Basic understanding of SvelteKit and Javascript
Node.js LTS version
An account in the Storyblok App
Create a Sveltekit project
Let’s create a Sveltekit project following the official installation guide:
npm init svelte@next my-app
cd my-app
npm install
npm run dev
When creating your new project, you will be asked if you want to set up some basic tooling like TypeScript. For the purpose of our project, you can select the basic skeleton project without Typescript and Playwright browser testing. We also don't require Eslint or Prettier, but feel free to set these things up according to your needs.
There is a Sveltekit Plugin for VS Code that helps with syntax highlighting.
You should now be able to see the SvelteKit App in your browser when you open https://localhost:3000:

Configuration of the space
Create a new space in the Storyblok app by clicking + Create new space and choosing the Create new space {1} option. Pick a name for it {2}.

Now, a Storyblok space with sample content has been created. If you open the Home story you will see the Visual Editor on your screen:

Understand what represents Story in our Storyblok Guide.
Enabling the Visual Editor
To see your website in the Storyblok Visual Editor you need to set the default environment URL. For that, in your space, open Settings > Visual Editor {1} and set the Location field to https://localhost:3000/ {2}:

Now go back to the Home story under the Content section. You'll see the Visual Editor when you open it, but you won't see your SvelteKit application yet.
Setting up a HTTPS Connection
If you are working with the Visual Editor V2, you’ll need to make a slight change to your svelte.config.js
and add the https: true
there in the server configuration. This is because the V2 requires a secure connection through HTTPS.
const config = {
kit: {
vite: {
server: {
https: true
}
},
},
};
Now, open the Config tab {1} on the right-hand form, and set the Real Path to “/” {2}. Save, and if you’re still running your SvelteKit app, you will see it now in the Visual Editor.

Connecting SvelteKit to Storyblok
First of all, let’s install @storyblok/svelte, our official SDK for all things Svelte & SvelteKit:
npm install @storyblok/svelte
# yarn add @storyblok/svelte
It allows you to interact with Storyblok API and enable the real-time editing experience. Let's configure it.
First of all, you need to grab your access token from your space Settings > Access Token:

Now let’s create a __layout.svelte file in the src/routes folder of our SvelteKit app. Here we can initialize the library, add the ApiPlugin and the access token of our Storyblok space:
<script context="module">
import { storyblokInit, apiPlugin } from "@storyblok/svelte";
storyblokInit({
accessToken: "your-preview-token",
use: [apiPlugin]
});
</script>
<main>
<slot/>
</main>
storyblokInit sets up the connection with the space. It initializes the Storyblok Bridge, that allows us to enable the real-time editing experience inside the Visual Editor. The function also provides an instance of the Storyblok API client that we can use to retrieve content from Storyblok.
If you are planning to use the Storyblok API client to call the REST API, make sure to include the ApiPlugin when initializing the storyblokInit() function.
Now, add all the components that you want to link to Storyblok in the components object in the storyblokInit()
function. This will link them to their representation in the Storyblok space. You can load all of them at the same time by adding them to the list, like so:
<script context="module">
import { storyblokInit, apiPlugin } from "@storyblok/svelte";
import Feature from '../components/Feature.svelte';
import Grid from '../components/Grid.svelte';
import Page from '../components/Page.svelte';
import Teaser from '../components/Teaser.svelte';
storyblokInit({
accessToken: "your-preview-token",
use: [apiPlugin],
components: {
feature: Feature,
grid: Grid,
page: Page,
teaser: Teaser,
},
});
</script>
<main>
<slot/>
</main>
Fetching the Content
Now you can use the useStoryblokApi()
in the index.svelte
to get your stories from the Storyblok CDN API:
<script context="module">
import { useStoryblokApi } from "@storyblok/svelte";
export async function load(){
const storyblokApi = useStoryblokApi();
const { data } = await storyblokApi.get("cdn/stories/home", { version: "draft",
});
return {
props:{ story: data.story }
}
}
</script>
Make sure to adjust the path according to your content structure if you structured your project differently.
Listening to changes in the Visual Editor
To enable the life editing experience, you can use the useStoryblokBridge()
function provided from @storyblok/svelte:
<script>
import { onMount } from "svelte";
import {useStoryblokBridge, StoryblokComponent } from "@storyblok/svelte";
export let story;
onMount(() => {
useStoryblokBridge(story.id, (newStory) => (story = newStory));
});
</script>
<div>
{#if story}
<StoryblokComponent blok={story.content} />
{/if}
</div>
Adding Components
As you may have already seen, the content in Storyblok is structured as components (or blocks). We can have stories, that are composed of different components. You can see an example in the Home story of our new space.
If you want to learn more about how the content is structured in Storyblok, you can read this guide.
In our example, we have created 4 example components in the src/components folder:
Feature
Grid
Page
Teaser
To make your components editable in the Storyblok Visual Editor, you have to add the use:storyblokEditable={blok}
action to the root of each component that you are loading in your storyblokInit
. For example, in Teaser.svelte
:
<script>
import { storyblokEditable } from "@storyblok/svelte";
export let blok;
</script>
<div use:storyblokEditable={blok}>
{ blok.headline }
</div>
Use the StoryblokComponent to load them by passing the blok property.
The blok is the actual blok data coming from Storyblok’s Content Delivery API.
One last thing
Please note that currently, you need to add 'axios' to the optimizeDeps object in your svelte.config.js.
:
import adapter from '@sveltejs/adapter-auto';
const config = {
kit: {
adapter: adapter(),
vite: {
optimizeDeps: {
include: ['axios'],
},
},
},
};
export default config;
And that’s it. When you now check out your story in the Visual Editor, the Storyblok JS Bridge is enabled, and you can make real-time changes:

Wrapping up
And that’s it - congrats for making it until this point! You should now have a fully functioning SvelteKit app all set up and ready to go with Storyblok, including the real-time changes and Visual Editor.
Resource | Link |
---|---|
Stackblitz SvelteKit Demo | https://stackblitz.com/edit/sveltekit-sdk-demo |
SvelteKit Docs | https://kit.svelte.dev/ |
Storyblok Visual Editor | https://www.storyblok.com/docs/editor-guides/visual-editor |
Storyblok Svelte SDK | https://github.com/storyblok/storyblok-svelte |
Storyblok Technologies Hub | https://www.storyblok.com/technologies |