---
title: @storyblok/preview-bridge
description: @storyblok/preview-bridge is Storyblok's official JavaScript bridge, enabling real-time preview in the Visual Editor.
url: https://www.storyblok.com/docs/libraries/js/preview-bridge
---

# @storyblok/preview-bridge

`@storyblok/preview-bridge` enables real-time preview of an iframe-embedded website within the [Visual Editor](/docs/concepts/visual-editor).

## Requirements

`StoryblokBridge` can only run in a browser environment.

-   **Modern web browser** (latest versions of Chrome, Firefox, Safari, Edge, etc.)

## Installation

To add the package to a project, run this command in the terminal:

```bash
npm install @storyblok/preview-bridge@latest
```

Access `StoryblokBridge` in the global scope, either directly or as a property of `window`:

```html
<body>
  <script>
    const storyblokBridge = new StoryblokBridge();
  </script>
</body>
```

## Usage

Following is a minimal implementation of the `StoryblokBridge` class. This webpage loads within the editor’s iframe and logs the story’s unsaved state each time the input in the Visual Editor changes.

```html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
  </head>
  <body>
    <script>
      const storyblokBridge = new StoryblokBridge();

      storyblokBridge.on("input", ({ story }) => {
        console.log(story);
      });
    </script>
  </body>
</html>
```

## API

### `StoryblokBridge`

The `StoryblokBridge()` constructor creates a bridge client that allows an iframe-embedded webpage to communicate with the Visual Editor.

```js
StoryblokBridge(parameters);
```

The constructor accepts the following optional parameters:

| Key | Description | Type |
| --- | --- | --- |
| `resolveRelations` | Define an array of [references](/docs/concepts/references) to other stories. To ensure that the linked data populates on each update, resolve any relations defined in the API request. Learn more about the [`resolve_relations` Content Delivery API parameter](/docs/api/content-delivery/v2/stories/examples/retrieving-stories-with-resolved-relations). | `array` |
| `resolveLinks` | Set to `"story"`, `"url"`, or `"link"` to track values of link fields. To ensure that the linked data populates on each update, resolve any links defined in the API request. Learn more about the [`resolve_links` Content Delivery API parameter](https://www.storyblok.com/docs/api/content-delivery/v2/stories/retrieve-a-single-story). | `string` |
| `preventClicks` | Enable or disable interactions within the preview area. Defaults to `false`. To allow standard click behavior, such as navigation between pages, set to `true`. | `boolean` |
| `customParent` | Define the parent app of the bridge. Defaults to `"https://app.storyblok.com"`. | `string` |
| `fallbackLang` | Set the fallback language of non-translated fields. | `string` |

```js
const storyblokBridge = new StoryblokBridge({
  resolveRelations: ["article.author", "article.category"],
  resolveLinks: "url",
  preventClicks: true,
  customParent: "https://your-storyblok-domain.com",
  fallbackLang: "de",
});
```

### Methods

`StoryblokBridge` has three prototype methods available on all instances:

-   `on()`
-   `pingEditor()`
-   `isInEditor()`

### `StoryblokBridge.prototype.on()`

```js
StoryblokBridge.prototype.on(event, callback);
StoryblokBridge.prototype.on([events_array], callback);
```

Create a listener to subscribe to the following editor events:

| Event | Description |
| --- | --- |
| `published` | The user published the story |
| `change` | The user saved the story |
| `input` | The user updated a field value or selected a version from [visual history](/docs/manuals/history#visual-history) |
| `enterEditmode` | The Visual Editor initialized |

The callback receives an event object. Each event type returns a matching object:

-   Published
    
    ```json
    {
      "reload": true,
      "action": "published",
      "slug": "home",
      "storyId": 24840769,
      "slugChanged": true
    }
    ```
    
-   Change
    
    ```json
    {
      "reload": true,
      "action": "change",
      "slug": "new-article",
      "storyId": 24840764,
      "slugChanged": false
    }
    ```
    
-   Input
    
    When a field value is updated
    
    ```jsonc
    {
      "action": "input",
      // Full story object
      "story": {}
    }
    ```
    
    When a visual history item is selected
    
    ```jsonc
    {
      "action": "input",
      // Minimal story object
      "story": {
        "id": 123,
        "content": {}
      }
    }
    ```
    
-   enterEditmode
    
    ```json
    {
      "reload": true,
      "action": "enterEditmode",
      "appVersion": "v2",
      "blockId": "2bc131ea-fac2-4210-b92d-c481f7f4d75b",
      "componentNames": {
        "feature": "Feature",
        "grid": "Grid",
        "page": "Page",
        "teaser": "Teaser"
      },
      "storyId": "24840769"
    }
    ```

The `StoryblokBridge.prototype.on()` method accepts a single event or an array of multiple events.

Inject the raw JSON of the story into the DOM on each input:

```js
storyblokBridge.on("input", ({ story }) => {
  document.getElementById("app").innerHTML = `
  <pre>
    ${JSON.stringify(story, null, 2)}
  </pre>
 `;
});
```

Reload the page when the user saves or publishes the story:

```js
storyblokBridge.on(["change", "published"], () => {
  location.reload(true);
});
```

Render a previous version of a story from visual history:

```js
storyblokBridge.on("input", ({ story }) => {
  // This function renders stories in your UI framework
  const renderStory = () => {};
  // The visual history payload is minimal, and only contains the id and content fields
  renderStory(story.content);
});
```

### `StoryblokBridge.prototype.pingEditor()`

```js
StoryblokBridge.prototype.pingEditor(callback);
```

Returns the full `StoryblokBridge` instance if the user previews the webpage within the Visual Editor.

The callback function receives a `payload` parameter that indicates the state of the preview within the editor.

```js
storyblokBridge.pingEditor((payload) => {
  console.log(payload);
});
```

### `StoryblokBridge.prototype.isInEditor()`

```js
StoryblokBridge.prototype.isInEditor(callback);
```

Returns `true` if the user previews the webpage within the Visual Editor and `false` if not. This method can only run in the callback function of `pingEditor()`.

```js
storyblokBridge.pingEditor(() => {
  if (storyblokBridge.isInEditor()) {
    // For example, fetch draft content
  } else {
    // For example, fetch published content
  }
});
```

## Pagination

-   [Previous: Angular SDK](/docs/libraries/js/angular-sdk)
-   [Next: Rich Text](/docs/libraries/js/rich-text)
