The Storyblok Bridge V1

Outdated:

This documentation is for the Storyblok bridge Version 1. Please check out our documentation for Version 2: Storyblok Bridge V2.

To build a bridge between Storyblok and your website, there needs to be included a script on your page. This script will communicate via iframe with Storyblok to tell the editing interface which component needs to be opened when the user clicks on it.

This is done using a simple HTML comment before that element which is shipped in the draft JSON by adding the key _editable to each component.

Include the script inside your <body> tag

<script src="//app.storyblok.com/f/storyblok-latest.js?t=YOUR_TOKEN" type="text/javascript">
</script>

You can see the preview token (= YOUR_TOKEN) via the dashboard of your space. You can also conditionally exclude the script tag if the user is not in the edit mode.

Methods to check for the edit mode:

  • Check for the URL parameter _storyblok
  • Check for a cookie (You could set a cookie the first time the url has _storyblok in it)

Usage

For a server rendered website the following code will reload your website as soon the user saves or publishes a story.

// Optionally init if you have not provided the ?t parameter to the script tag already.
storyblok.init({
  accessToken: 'your_token'
})

storyblok.on(['published', 'change'], function() {
  location.reload(true)
})

storyblok.pingEditor(function() {
  if (storyblok.inEditor) {
    storyblok.enterEditmode()
  }
})

Events

You can listen to events calling the on handler:

storyblok.on('event_name', function(data) {
  console.log(data);
})

For the published event this would look like:

storyblok.on('published', function(data) {
  console.log(data);
  // invalidate cache, ...
})

For the app “Sync Button” there is a special event you can listen to:

storyblok.on('customEvent', function(data) {
  if (data.event == 'start-sync') {
    // Do sync
  }
})

You get a 404 error after changing the slug of a Story?
If you use Storyblok with serverside rendering and want to reload whenever the content changed you need to make an additional check on the slugChanged attribute. This makes sure that the page doesn’t throw a 404 error if you change the slug:

Published and Change event

storyblok.on(['published', 'change'], function(event) {
  if (!event.slugChanged) {
    location.reload(true)
  }
})

Input event

storyblok.on('input', function(event) {
    // Access currently changed but not yet saved content via: 
   console.log(event.story.content)
})

Use the addComments functionality to add the _editable properties to all blocks in your content.

Event Will be emitted
input after a user changes the value of a field
change after the user saves the content
published after the user clicks publish
unpublished after the user clicks unpublish
enterEditmode after the editor has been initialized in the editmode
customEvent custom event used by third party plugins

Functions

storyblok.init(config)

config Object

  • accessToken String: The private token of the Content Delivery API to receive draft versions of content. You can find it in your space dashboard at https://app.storyblok.com.
  • customParent String: If you are using the Storyblok editor on your own domain a url needs to be provided. Default is: https://app.storyblok.com.

Example

storyblok.init({
  accessToken: 'xf5dRMMjltLzKOcNgMaU9Att'
})

storyblok.addComments(story_object, story_id)

Enhance the event data with the _editable properties across all components.

window.storyblok.on('input', (payload) => {
  console.log(payload.story.content)
  // Output: {
  //  "story": {
  //    "id": 123,
  //    "content": {
  //      "body":
  //        {
  //          "component":"hero",
  //          "headline": "123123"
  //        },
  //        {
  //          "component":"hero",
  //          "headline": "123123"
  //        }
  //      ]
  //    }
  //  }
  //}

  let updatedStoryContent = window.storyblok.addComments(payload.story.content, payload.story.id)
  console.log(updatedStoryContent)

  // Output: {
  //  "story": {
  //    "id": 123,
  //    "content": {
  //      "component": "page",
  //      "body": [
  //        {
  //          "component":"hero",
  //          "headline": "123123",
  //          "_editable": "<!- correct editable tag -->"
  //        },
  //        {
  //          "component":"hero",
  //          "headline": "123123",
  //          "_editable": "<!- correct editable tag -->"
  //        }
  //      ],
  //      "_editable": "<!- correct editable tag -->"
  //    }
  //  }
  //}
  // TODO: Set your state
})

Example

storyblok.isInEditor() and pingEditor()

With these functions you can check if your user has opened a page inside Storyblok.

Example

storyblok.pingEditor(() => {
  if (storyblok.isInEditor()) {
    // getStory('draft')
  } else {
    // getStory('published')
  }
})

storyblok.get(query, success, error)

Get a single content entry in the frontend.

  • query Object
    • version String: ‘draft’ or ‘published’. Default is ‘published’
  • success Function: Success callback
  • error Function: Error callback

Example

storyblok.get({
  slug: 'home', 
  version: 'draft'
}, (data) => {
  var story = data.story
})

storyblok.getAll(query, success, error)

Get multiple content entries

  • query Object
    • with_tag, String
    • starts_with, String
    • version, String
    • sort_by, String
    • filter_by, String
    • per_page, String
    • page, String
  • success Function, Success callback
  • error Function, Error callback

Example

storyblok.getAll({
  version: 'draft'
}, (data, xhrResponse) => {
  var total = xhrResponse.getResponseHeader('Total')
  var stories = data.stories
})

Troubleshooting

Why is the live preview not working?

Check if you are not redirecting to another url by clicking “Open draft” in the top right submenu. The url should contain the query parameter _storyblok.

How to validate if the user is viewing your site in the Storyblok editor?

If the user opens your page in Storyblok, we add a few parameters which you can use to securely validate their use of the edit mode.

You will need that validation to load the right version of your content to the right users. The draft version is for the editor and the published version is for the public.

A simple validation would be to check if there is the _storyblok parameter in url. This could be done in the frontend or in the backend. But for a secure check we recommend to implement the logic in the backend and validate the _storyblok_tk parameter.

Here are some examples of how to securely check if the user is in edit mode:

import crypto from 'crypto'
// getQueryParam = access requests URL param by name

let validationString = getQueryParam('_storyblok_tk[space_id]') + ':' + YOUR_PREVIEW_TOKEN + ':' + getQueryParam('_storyblok_tk[timestamp]')
let validationToken = crypto.createHash('sha1').update(validationString).digest('hex')
if (getQueryParam('_storyblok_tk[token]') == validationToken && 
    getQueryParam('_storyblok_tk[timestamp]') > Math.floor(Date.now()/1000)-3600) { 
    // you're in the edit mode.
    this.editMode = true 
}
$sb = $app['request']->query->get('_storyblok_tk');
if (!empty($sb)) {
    $pre_token = $sb['space_id'] . ':' . YOUR_PREVIEW_TOKEN . ':' . $sb['timestamp'];
    $token = sha1($pre_token);
    if ($token == $sb['token'] && (int)$sb['timestamp'] > strtotime('now') - 3600) {
        $app['config.storyblok.edit_mode'] = true;
        // you're in the edit mode.
    }
}
hint:

In the demo above we expect 1 hour as the time of a token being valid. So basically that an editor will work max 1 hour on one page before switching to another entry inside the editor or refreshing the browser window. You can extend that by adjusting 3600 with the value you need.

These are the parameters Storyblok appends to your url:

Param Description
_storyblok the content entries ID
_storyblok_tk[space_id] the space ID
_storyblok_tk[timestamp] a timestamp
_storyblok_tk[token] a validation token. Combination of space_id, timestamp and your preview_token
_storyblok_release currently selected id of a release
_storyblok_lang currently selected language
_storyblok_c content type of the story