npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@alphabite/medusa-storyblok

v0.2.8

Published

Alphabite's Medusa Storyblok Plugin

Downloads

1,927

Readme

Medusa Storyblok Plugin

npm version npm downloads License Discord

A powerful plugin that seamlessly syncs your Medusa products with Storyblok, enabling headless content management for your e-commerce product catalog.

💬 Need Help? Join our Discord community for support, questions, and discussions!

Table of Contents

Features

  • Automatic Product Sync: Products created in Medusa are automatically synced to Storyblok
  • Image Management: Product and variant images are automatically uploaded to Storyblok with smart deduplication
  • Bi-directional Sync: Content updates in Storyblok sync back to Medusa via webhooks
  • Variant Support: Full support for product variants with individual image galleries
  • Asset Organization: Creates dedicated folders for each product's assets
  • Bulk Sync: Sync multiple products or your entire catalog at once
  • Cleanup: Automatically removes assets and folders when products are deleted
  • Image Optimization: Built-in image optimization with configurable quality and dimensions

Installation

yarn add @alphabite/medusa-storyblok

Configuration

1. Add Plugin to Medusa Config

In your medusa-config.js or medusa-config.ts, add the plugin to the plugins array:

import { AlphabiteStoryblokPluginOptions } from "@alphabite/medusa-storyblok";

plugins: {
  [
    // ... other plugins
    {
      resolve: "@alphabite/medusa-storyblok",
      options: {
        accessToken: process.env.STORYBLOK_ACCESS_TOKEN,
        region: process.env.STORYBLOK_REGION, // "eu" or "us"
        personalAccessToken: process.env.STORYBLOK_PAT,
        spaceId: process.env.STORYBLOK_SPACE_ID,
        productsParentFolderId: process.env.STORYBLOK_PRODUCTS_PARENT_FOLDER_ID,
        productsParentFolderName: "products",
        deleteProductOnSbProductStoryDelete: false,
        webhookSecret: process.env.STORYBLOK_WEBHOOK_SECRET,
        imageOptimization: {
          quality: 80,
          width: 800,
        },
      } satisfies AlphabiteStoryblokPluginOptions,
    },
  ];
}

2. Environment Variables

Add the following environment variables to your .env file:

# Storyblok Access Token (Content Delivery API - read-only)
STORYBLOK_ACCESS_TOKEN=your_access_token

# Storyblok Personal Access Token (Management API - write access)
STORYBLOK_PAT=your_personal_access_token

# Storyblok Space ID
STORYBLOK_SPACE_ID=your_space_id

# Storyblok Region (eu or us)
STORYBLOK_REGION=eu

# Parent Folder ID where product stories will be created
STORYBLOK_PRODUCTS_PARENT_FOLDER_ID=your_folder_id

# Optional: Webhook secret for validating Storyblok webhooks
STORYBLOK_WEBHOOK_SECRET=your_webhook_secret

Configuration Options

| Option | Type | Required | Default | Description | | ------------------------------------- | ------------------------ | -------- | --------- | ----------------------------------------------------------- | | accessToken | string | ✅ | - | Storyblok Access Token for Content Delivery API (read-only) | | personalAccessToken | string | ✅ | - | Personal Access Token for Management API (write access) | | spaceId | string | ✅ | - | Your Storyblok Space ID | | region | "eu" \| "us" | ✅ | - | Storyblok region of your space | | productsParentFolderId | string | ✅ | - | Folder ID where product stories will be created | | productsParentFolderName | string | ✅ | - | Folder name (usually "products") | | version | "draft" \| "published" | ❌ | "draft" | Version of stories to fetch | | webhookSecret | string | ❌ | - | Secret for validating Storyblok webhooks | | deleteProductOnSbProductStoryDelete | boolean | ❌ | false | Delete Medusa product when Storyblok story is deleted | | imageOptimization | object | ❌ | - | Image optimization settings | | imageOptimization.width | number | ❌ | 800 | Target image width in pixels | | imageOptimization.quality | number | ❌ | 80 | Image quality (1-100) | | imageOptimization.mapImageUrl | function | ❌ | - | Custom function to transform image URLs |

Why Two Access Tokens?

Access Token (accessToken):

  • Used for reading content from Storyblok (Content Delivery API)
  • Read-only access
  • Found in: Storyblok → Settings → Access Tokens

Personal Access Token (personalAccessToken):

  • Used for creating, updating, and deleting stories (Management API)
  • Required to grant write access for syncing products
  • How to get it:
    1. Go to your Storyblok account (top-right corner)
    2. Click on "My Account"
    3. Go to "Account Settings"
    4. Navigate to "Personal Access Tokens"
    5. Create a new token with appropriate permissions

Important: Make sure you are working with the correct spaceId, since the PAT grants write access to all of your Storyblok spaces.

Storyblok Setup

1. Create a Products Folder

  1. In Storyblok, go to the Content tab and create a folder where all product stories will be stored (e.g., "products")
  2. Open the folder and note the Folder ID from the URL:
    https://app.storyblok.com/#/me/spaces/{space_id}/stories/0/0/{folder_id}
                                                                    ↑ This is your folder ID
  3. Use this ID for productsParentFolderId in your configuration
  4. Use the name of the folder for productsParentFolderName

2. Create Required Bloks

Gallery Image Blok

Create a blok named galleryImage with the following fields:

| Field Name | Type | Required | Description | | ------------- | ------------- | -------- | ----------------------------------- | | image | Asset (Image) | ✅ | The image asset | | isThumbnail | Boolean | ✅ | Whether this image is the thumbnail |

Product Variant Blok

Create a blok named productVariant with the following fields:

| Field Name | Type | Required | Description | | ------------------------ | ------ | -------- | ----------------------------------------------- | | title | Text | ✅ | Variant title/name | | medusaProductVariantId | Text | ✅ | Medusa variant ID (for syncing) | | gallery | Blocks | ❌ | Gallery of images (accepts galleryImage blok) |

Product Content Type

Create a content type named product with the following fields:

| Field Name | Type | Required | Description | | ----------------- | ------ | -------- | --------------------------------------------------- | | medusaProductId | Text | ✅ | Medusa product ID (for syncing) | | title | Text | ✅ | Product title/name | | gallery | Blocks | ❌ | Product image gallery (accepts galleryImage blok) | | variants | Blocks | ❌ | Product variants (accepts productVariant blok) |

Note: You can add any additional fields you need for your content management (description, SEO fields, custom attributes, etc.)

3. Configure Webhooks (Optional but Recommended)

To enable bi-directional sync (Storyblok → Medusa), set up webhooks:

  1. Go to Storyblok → Settings → Webhooks
  2. Create webhooks with the following URLs (replace with your backend URL):
    https://your-medusa-backend.com/storyblok/webhook/story/update?token=YOUR_WEBHOOK_SECRET
    https://your-medusa-backend.com/storyblok/webhook/story/delete?token=YOUR_WEBHOOK_SECRET
  3. Select the appropriate events:
    • Story published (for update webhook)
    • Story deleted (for delete webhook)

Note: The webhook secret is passed as a query parameter ?token=YOUR_SECRET in the URL

Admin UI

The plugin provides a comprehensive admin UI for managing product synchronization with Storyblok.

Product Page Widget

On each product detail page in Medusa Admin, you'll see a Storyblok widget with:

When Product is Synced:

  • 🟢 Green "Synced" status badge
  • "Open in Storyblok" button - Opens the product story in Storyblok (new tab)

When Product is Not Synced:

  • 🔴 Red "Not Synced" status badge
  • "Sync to Storyblok" button - Creates the story in Storyblok with all variants and images

Storyblok Management Page

Access via Medusa Admin sidebar → "Storyblok"

This dedicated page shows all your Medusa products with their sync status:

Features:

  • Product List - View all products with sync status
  • Individual Sync - Each row has a "Sync" or "Open in Storyblok" button
  • Bulk Selection - Checkboxes to select multiple products
  • Sync Selected - Sync only checked products
  • Sync All - Bulk sync all products at once

Status Indicators:

  • 🟢 Synced - Product exists in Storyblok, shows "Open in Storyblok" button
  • 🔴 Not Synced - Product doesn't exist in Storyblok, shows "Sync" button

How It Works

Medusa → Storyblok Sync

1. Product Creation

When a product is created in Medusa:

  • ✅ A new story is created in Storyblok with the product data
  • ✅ A dedicated asset folder is created (named after product slug)
  • ✅ Product thumbnail is uploaded to the folder
  • ✅ All product images are uploaded to the folder
  • ✅ Images are added to the product's gallery with proper thumbnail marking
  • ✅ Product variants are NOT created automatically (see below)

2. Product Update

When a product is updated in Medusa:

  • ✅ Only the product handle (slug) is synced to Storyblok
  • ❌ Other fields (title, images, etc.) are NOT synced from Medusa to Storyblok

Important: Once a product is synced to Storyblok, content management should happen in Storyblok. Updates will sync back to Medusa via webhooks.

3. Product Deletion

When a product is deleted in Medusa:

  • ✅ The Storyblok story is deleted
  • ✅ The product's asset folder is deleted
  • ✅ All images in the folder are deleted
  • ✅ Complete cleanup - no orphaned assets

4. Variant Creation

When a variant is created in Medusa:

  • ✅ Variant is added to the product story in Storyblok
  • ✅ Variant thumbnail is uploaded (if exists)
  • ✅ Variant images are uploaded to the product's folder
  • ✅ Images are added to the variant's gallery

Important: When a new product is created, the plugin will automatically also create its default variant (or the multiple variants you have added during creation), and it will upload the images added to the product or variants during creation

5. Variant Deletion

When a variant is deleted in Medusa:

  • ✅ The variant is removed from the product story in Storyblok
  • ⚠️ Associated images remain in the folder (may be used by product or other variants)

Storyblok → Medusa Sync

When a product story is published in Storyblok:

  • ✅ Product handle is synced back to Medusa
  • ✅ Product thumbnail URL is synced to Medusa
  • ✅ Product images are synced to Medusa
  • ✅ Variant thumbnails are synced to Medusa
  • ✅ Image URLs point to optimized Storyblok CDN URLs

This enables your storefront to use Storyblok's CDN for images without additional fetches.

Image Management

Smart Deduplication

The plugin intelligently handles image uploads:

  • ✅ Checks if an image already exists in the folder before uploading
  • ✅ Reuses existing assets when the same image is used across variants
  • ✅ Prevents duplicate uploads when variants share product images
  • ✅ Case-insensitive filename matching

Folder Organization

Each product gets its own asset folder:

products/
  └── my-product-slug/
      ├── thumbnail.webp
      ├── image1.png
      ├── image2.png
      └── variant-image.jpg

Image Optimization

Images served from Storyblok are automatically optimized:

  • Configurable width and quality
  • Automatic WebP conversion
  • CDN delivery
  • Custom transformation functions supported

Troubleshooting

Products not syncing

  1. Check that all required environment variables are set
  2. Verify your Personal Access Token has write permissions
  3. Check Medusa logs for error messages
  4. Ensure the products parent folder exists in Storyblok

Images not uploading

  1. Verify product images have valid URLs
  2. Check that the asset folder exists (created automatically)
  3. Review Storyblok asset limits for your plan
  4. Check Medusa logs for upload errors

Webhooks not working

  1. Verify webhook URL is publicly accessible
  2. Check webhook secret matches in both Storyblok and Medusa config
  3. Review webhook logs in Storyblok dashboard
  4. Ensure webhook events are configured correctly

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

MIT

Support

For issues and questions:

Credits

Developed with ❤️ by Alphabite