Using Image Service on Private assets with Next.js

Contents
    Try Storyblok

    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.

    IMPORTANT:

    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.

    IMPORTANT:

    The project in this article was developed using the following versions of these technologies:

    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.

    app.storyblok.com
    Storyblok asset access tokens
    1
    2
    3
    4

    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.

    app.storyblok.com
    Storyblok v2 assets dashboard
    1
    2
    3

    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.

    hint:

    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.

    src/App.js
    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.

    src/App.js
    ...
    
    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

    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

    src/App.js
    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