Blurred image placeholder with Next.js image and Cloudinary

nicolaserny

Nicolas Erny

Posted on December 2, 2021

Blurred image placeholder with Next.js image and Cloudinary

Most of the time, we don't want to manage image optimizations ourselves. Libraries such as Next.js/image are handy to deal with responsive images. In addition to Next.js image, I often use Cloudinary, which is a media management service.
Two key benefits:

  • Use a CDN dedicated to our images
  • Easy to apply transformations to an image: a URL-based image API

Next.js provides excellent integration with Cloudinary. For example, we can use the following next.config.js file.

const cloudinaryBaseUrl = `https://res.cloudinary.com/${process.env.CLOUDINARY_CLOUD_NAME}/image/upload/`;
module.exports = {  
  images: {
    loader: "cloudinary",
    path: cloudinaryBaseUrl,
  },
};
Enter fullscreen mode Exit fullscreen mode

where the CLOUDINARY_CLOUD_NAME env variable contains our cloudinary cloud name.

We're ready to build a basic app to display an image using next/image and Cloudinary. Here's what a React code would be like:

 function Home({ exampleImage }) {
    return (
        <div className={styles.container}>            
            <main className={styles.main}>
                <h1 className={styles.title}>Blurred image placeholder</h1>
                <h2 className={styles.subtitle}>with Next.js image and cloudinary</h2>
                <div className={styles.imagewrapper}>
                    <Image
                        src={exampleImage.src}
                        alt="Example"
                        width="1920"
                        height="1280"
                        layout="responsive"
                        quality="75"
                        sizes="60vw"                        
                    />
                </div>
            </main>
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

React code example

It would be nice to display a blurry image while the browser loads the real one.
Blurred image placeholder
But, unfortunately, next/image does not generate the blurred placeholder automatically when we use the Cloudinary loader.

Let's try to add a blurred image placeholder. Next/image provides two properties: placeholder and blurDataURL. We will rely on Cloudinary to get a low-quality, blurred picture. It leads to the following function to generate a base64 encoded data URL:

export async function getBase64ImageUrl(imageId: string): Promise<string | undefined> {
    const response = await fetch(`${process.env.CLOUDINARY_BASE_URL}w_100/e_blur:1000,q_auto,f_webp${imageId}`);
    const buffer = await response.arrayBuffer();
    const data = Buffer.from(buffer).toString('base64');
    return `data:image/webp;base64,${data}`;
}
Enter fullscreen mode Exit fullscreen mode

Finally, we have to generate the data URL at compile-time. With Next.js, it's pretty straightforward by implementing the getStaticProps function:

export async function getStaticProps() {
    const imageSrc = process.env.CLOUDINARY_EXAMPLE_IMAGE_SRC;
    if (!imageSrc) {
        throw new Error('Missing CLOUDINARY_EXAMPLE_IMAGE_SRC env variable');
    }

    const blurDataUrl = await getBase64ImageUrl(imageSrc);
    return {
        props: {
            exampleImage: {
                src: imageSrc,
                blurDataUrl: blurDataUrl,
            },
        },
    };
}
Enter fullscreen mode Exit fullscreen mode

where the CLOUDINARY_EXAMPLE_IMAGE_SRC env variable contains our cloudinary image id.

So here's the final version of the React code:

function Home({ exampleImage }: InferGetStaticPropsType<typeof getStaticProps>) {
    return (
        <div className={styles.container}>            
            <main className={styles.main}>
                <h1 className={styles.title}>Blurred image placeholder</h1>
                <h2 className={styles.subtitle}>with Next.js image and cloudinary</h2>
                <div className={styles.imagewrapper}>
                    <Image
                        src={exampleImage.src}
                        alt="Example"
                        width="1920"
                        height="1280"
                        layout="responsive"
                        quality="75"
                        sizes="60vw"
                        placeholder="blur"
                        blurDataURL={exampleImage.blurDataUrl}
                    />
                </div>
            </main>
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

You can find the source code on Github.
This has been helpful for me in my projects. Hopefully it helps you as well.

💖 💪 🙅 🚩
nicolaserny
Nicolas Erny

Posted on December 2, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related