---
title: Introduction
description: Discover Storyblok's documentation with comprehensive developer guides, user manuals, API references, and examples to help you get the most out of the headless CMS platform.
url: https://storyblok.com/docs/plugins/tool-plugins
---

# Introduction

Tool plugins extend Storyblok’s Visual Editor by adding custom tool windows as standalone applications embedded in iframes. They communicate with Storyblok via [cross-window messaging](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) and the [Management API](/docs/api/management/).

> [!NOTE]
> Tool plugins are a premium feature. Learn more on the [pricing](/pricing) page.

Content editors open tools directly from the Visual Editor. For example, the [Autosave plugin](https://www.storyblok.com/apps/autosave), allowing editors to access tool functionality related to the story being edited. Common use cases for tools include:

-   Analyzing content
-   Transforming content
-   Performing actions on content

Examples in the app directory include tools such as [Export](https://www.storyblok.com/apps/export) and [Import](https://www.storyblok.com/apps/import) Translatable Fields and [Autosave](https://www.storyblok.com/apps/autosave).

Tool plugins function similarly to [space plugins](/docs/plugins/space-plugins) but have some key differences. Tool plugins embed directly in the Visual Editor and can access the story being edited, while space plugins cannot.

## **Integrating with the Visual Editor**

Your plugin is currently a standalone app embedded in Storyblok. To connect it to Storyblok’s Visual Editor, use `window.postMessage`.

### Setting the Height

Tools appear stacked vertically in the Visual Editor, with iframes set at a specific height in pixels. When the height of your tool changes (e.g., on initial load), notify the Visual Editor to adjust the iframe height using:

```javascript
window.parent.postMessage({
  action: 'tool-changed',
  tool: 'my-tool-plugin-name',
  event: 'heightChange',
  height: 500
}, '*');
```

In this example, `height` is set to `500` px. The `tool` value must match the plugin's slug in settings. Use minimal vertical space to avoid blocking tools below, as stacking order can’t be controlled.

### Automatic Height Adjustment

To auto-adjust height, register a `ResizeObserver` that updates the iframe height when document height changes. Set `html` element’s height to `auto`:

```html
html {
  height: auto;
  overflow: hidden;
}
```

In your component:

```javascript
const handleResize = () => {
  const height = document.body.clientHeight;
  window.parent.postMessage({
    action: 'tool-changed',
    tool: 'storyblok-gmbh@jl-dev-tool',
    event: 'heightChange',
    height,
  }, "*");
}

const observer = new ResizeObserver(handleResize);
observer.observe(document.body);
```

Disconnect the observer when the component unmounts:cpd

```javascript
observer.disconnect();
```

### Reading the Story

To read the story in the Visual Editor, set up an event listener:

```java
const handleMessage = (e) => {
  console.log(e.data);
};

window.addEventListener('message', handleMessage, false);
```

Remove the listener on component unmount:

```javascript
window.removeEventListener('message', handleMessage, false);
```

Request context by sending a message:

```javascript
window.parent.postMessage({
  action: 'tool-changed',
  tool: 'my-plugin-name',
  event: 'getContext'
}, "*");
```

The Visual Editor will respond with the story context, including story details and language, in this format:

```json
{
  "action": "get-context",
  "story": {
    "name": "hello444",
    "uuid": "45bbd2c4-b418-4737-8f4f-d893ec1f7f10",
    "content": { ... },
    ...
  },
  "language": ""
}
```

## **Integrating with the Management API**

Server-side code can interact with the Management API by reading `accessToken` and `spaceId` from `http.IncomingMessage`:

```javascript
const { query } = req;
const sessionStore = sessionCookieStore(authHandlerParams)({ req, res });
const { accessToken, region, spaceId } = await sessionStore.get(query);
```

The `@storyblok/app-extension-auth` library automatically appends `storyId` and `spaceId` as query parameters, enabling access to `accessToken` and `region` from the session store. With these values, send Management API requests such as:

```javascript
new StoryblokClient({
    oauthToken: `Bearer ${accessToken}`,
    region,
})
.get(`spaces/${spaceId.toString(10)}/stories`, { sort_by: 'updated_at:desc' });
```

> [!TIP]
> Take a look at our [starter projects](https://github.com/storyblok/space-tool-plugins/tree/main/tool-plugins) for similar examples.

To update the current story, use the Management API. Note that changes won’t appear immediately in the Visual Editor – prompt the user to manually refresh the window to see updates.

## Pagination

-   [Previous: Migration to Vue 3](/docs/plugins/field-plugins/migration-to-vue-3)
-   [Next: Introduction](/docs/plugins/space-plugins)
