Using Image Service on Private assets with Next.js
Storyblok is the first headless CMS that works for developers & marketers alike.
In this tutorial, we will learn how to use Storyblok image service on private assets, We will add images to our application with image service and get signed_url
to view the images as private assets.
To use image services on private assets, you will have to use the v1 of image services as the v2 doesn’t support private assets at the moment.
Requirements
The following are required for this tutorial:
Basic knowledge of Next.js and React
Node, yarn (or npm), and npx installed
An account on Storyblok to manage content
If you're new to Storyblok, We highly recommend our tutorial Add a headless CMS to Next.js in 5 minutes.
The project in this article was developed using the following versions of these technologies:
- React.js v18.0.0
- Node.js v16.14.2
- Npm v8.3.0
- @storyblok/react
The GitHub repository with all the code samples is available here.
Storyblok Image Service
Image Service in Storyblok helps users perform activities like increasing image brightness, resizing images, and crop images on the go by adding specific parameters to the image url.
But this doesn’t work on private assets as it does on public assets. This is because to show a private asset on a webpage; we need to first get the signed_url of the asset by running it through the @storyblok/react In the next section, we will build a demo React app to learn how to get the signed_url
of a private asset and use image services on the asset.
Building a demo App for Image Services
Start by generating a new React app with create-react-app using the command below:
npx create-react-app storyblok-image-service
After that, navigate to the project folder and run the command below to install @storyblok/react. We will use this to get the signed_url
of our private assets.
npm install @storyblok/react
Now, go to your storyblok space, Click on settings {1} on the left sidebar, and click the Access Tokens {2} on the settings page. Select Assets {3} as Access level, click on the Generate {4} Token button and copy the asset token to the React application.

Storyblok asset access tokens
Next, We need to copy the url of a Private asset from our Storyblok space. Click on Assets {1} on the left sidebar, on the assets page, click on private assets and highlight and copy URL {2}. If you don’t have private assets, you can click on the Upload {3} button on the top-right to add.

Storyblok v2 assets dashboard
We now have a private asset URL and a token with which we can generate a signed_url
from the private asset. Let’s head over to our React app to get a signed_url
of our private asset.
You can learn more about Storyblok React SDk here.
Getting the Signed_url of a Private Asset
We need to first initialize a Storyblok client with the asset token we got from our space. Go to src/App.js
in the React App and replace what you have there with the code below.
import { useEffect, useState } from "react";
import { storyblokInit, apiPlugin, getStoryblokApi } from "@storyblok/react";
storyblokInit({
accessToken: "YOUR ACCESS TOKEN",
use: [apiPlugin],
});
Next, let’s store the private asset URL in a variable, get the signed_url
with the Storyblok client we initialized above, and show the image in our app. Add the code to src/App.js
to do that.
...
const privateAsset =
"https://a.storyblok.com/f/143584/757x758/f7b07f187f/screenshot-2022-02-11-at-11-13-41-am.png";
const App = () => {
const storyblokApi = getStoryblokApi();
const [signedUrl, setSignedUrl] = useState("");
useEffect(() => {
const fetchSpace = async () => {
try {
const params = {
filename: privateAsset,
version: "draft",
};
const { data } = await storyblokApi.get("cdn/assets/me", params);
} catch (err) {
console.log(err);
}
};
fetchSpace();
}, [storyblokApi]);
return (
<div>
<h2 style={{ textAlign: "center" }}>Image Services on Private Asset</h2>
<div style={{ display: "flex", flexWrap: "wrap" }}>
{signedUrl && (
<div>
<img src={signedUrl} alt="Storyblok Private Asset" />
</div>
)}
</div>
</div>
);
};
export default App;
We have now successfully generated the signed_url
of a private assets. Now, let's use image services on the private asset.
Image Services on Private assets
We can use image services on public assets by simply appending /m
to the end of the URL and adding an image service param or filter next to it e.g.
https://a.storyblok.com/f/39898/1000x600/d962430746/demo-image-human.jpeg/m/600x130
The param /600x130
added at the end is to resize the image to have a width of 600px
and a height of 130px
.
But when using image services on private assets, appending our desired filters won’t work. We will get an error like the one below

Error when using image service private assets without signed_url
For this to work, we first need to prepend https://private-img.storyblok.com/
to the signed_url
. Let’s test this in our app.
Let’s add a resize to the image using image services, update your src/App.js
file with the code below
import { useEffect, useState } from "react";
import { storyblokInit, apiPlugin, getStoryblokApi } from "@storyblok/react";
storyblokInit({
accessToken: "YOUR_ACCESS_TOKEN",
use: [apiPlugin],
});
const privateAsset =
"https://a.storyblok.com/f/143584/757x758/f7b07f187f/screenshot-2022-02-11-at-11-13-41-am.png";
const App = () => {
const storyblokApi = getStoryblokApi();
const [signedUrl, setSignedUrl] = useState("");
useEffect(() => {
const fetchSpace = async () => {
try {
const params = {
filename: privateAsset,
version: "draft",
};
const { data } = await storyblokApi.get("cdn/assets/me", params);
const imgServiceUrl = `https://private-img.storyblok.com/200x200/${encodeURIComponent(
data.asset.signed_url
)}`;
setSignedUrl(imgServiceUrl);
} catch (err) {
console.log(err);
}
};
fetchSpace();
}, [storyblokApi]);
return (
<div>
<h2 style={{ textAlign: "center" }}>Image Services on Private Asset</h2>
<div style={{ display: "flex", flexWrap: "wrap" }}>
{signedUrl && (
<div>
<img src={signedUrl} alt="Storyblok Private Asset" />
</div>
)}
</div>
</div>
);
};
export default App;
You should see the image appearing on your screen, and it will have the specified size. You can go ahead and try more image service parameters on it.
Conclusion
This tutorial teaches us how to use Storyblok’s image service with private assets. We also looked at how to get a signed_url
of a private asset, view a private asset, and use it for our application.
Image service and private asset resources
Resources | Link |
---|---|
Project Example Repo | https://github.com/iamfortune/Storyblok-image-service-private-assets |
Storyblok image service | https://www.storyblok.com/docs/image-service |
Private assets management with Storyblok | https://www.storyblok.com/cl/private-assets-management |
Accessing your data with Storyblok | https://www.storyblok.com/docs/guide/essentials/accessing-data |