Blurred image placeholder with Next.js image and Cloudinary
Tags: react, nextjs, cloudinary
Published: 2021-12-02 12:51:05

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.
```js
const cloudinaryBaseUrl = `https://res.cloudinary.com/${process.env.CLOUDINARY_CLOUD_NAME}/image/upload/`;
module.exports = {  
  images: {
    loader: "cloudinary",
    path: cloudinaryBaseUrl,
  },
};
```
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:
```js
 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>
    );
}
```
![React code example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2hvtomqctu29ixvp13jv.png)
 
It would be nice to display a blurry image while the browser loads the real one.
![Blurred image placeholder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2p1declmatraeaa8rekm.png) 
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:
```js
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}`;
}
```

Finally, we have to generate the data URL at compile-time. With Next.js, it's pretty straightforward by implementing the getStaticProps function:
```js
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,
            },
        },
    };
}
```
where the _CLOUDINARY_EXAMPLE_IMAGE_SRC_ env variable contains our cloudinary image id.

So here's the final version of the React code:
```js
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>
    );
}
```
You can find the source code on [Github](https://github.com/nicolaserny/next-image-cloudinary-example).
This has been helpful for me in my projects. Hopefully it helps you as well.