{"id":27805,"date":"2023-07-14T07:00:00","date_gmt":"2023-07-14T14:00:00","guid":{"rendered":"http:\/\/removing-and-changing-an-images-background-with-cloudinary-using-next.js-serverless-functions"},"modified":"2025-05-03T15:13:45","modified_gmt":"2025-05-03T22:13:45","slug":"removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions","title":{"rendered":"Change a Background With Cloudinary and Next.js"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>When dealing with images, often you want to be able to cut out the primary object and change the background, whether that\u2019s a pair of shoes you want to show in your store in a more life-like environment or if you simply want to change the background.<\/p>\n<p>But doing this manually can be a huge pain and take a lot of time!<\/p>\n<p>Instead, we can take advantage of Cloudinary AI using its <a href=\"https:\/\/cloudinary.com\/background-remover\">background removal<\/a> tool to cut out our images and swap in whatever background we\u2019d like.<\/p>\n<\/div>\n\n<div class=\"wp-block-cloudinary-markdown \"><p><a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\">See Code on GitHub<\/a><\/p>\n<p>Before diving into the specifics of changing backgrounds with Cloudinary, it\u2019s important to understand some basics of handling images in Next.js. In Next.js, images are typically managed using the <code>Image<\/code> component from <code>next\/image<\/code>. This component requires specific props such as <code>src<\/code>, <code>width<\/code>, <code>height<\/code>, and <code>alt<\/code>. These props help in automatically determining the image\u2019s dimensions, which is crucial for preventing Cumulative Layout Shift (CLS) while the image is loading.<\/p>\n<p>Additionally, to make an image responsive in Next.js, you can utilize the <code>next\/image<\/code> component along with the <code>layout <\/code>attribute. This attribute accepts three values: \u2018fill\u2019, \u2018responsive\u2019, and \u2018fixed\u2019, allowing for greater flexibility in how the image is displayed across different screen sizes.<\/p>\n<p>For instance, you can start by importing the image component and defining the image path in the component\u2019s <code>src<\/code> props. Wrap your image and other elements in a root element, like a fragment or a div, and insert other necessary HTML tags like an <code>H1<\/code> tag.<\/p>\n<h2>Step 0: Setting Up a Workspace<\/h2>\n<p>In my example, I\u2019m using <a href=\"https:\/\/nextjs.org\/\">Next.js<\/a>, which allows me to set up API endpoints that use serverless functions to proxy my custom uploads to Cloudinary.<\/p>\n<p>Whether or not you\u2019re following along with Next.js, the code we\u2019ll use should be transferrable to any other node.js-based application.<\/p>\n<p>To get started, I used my <a href=\"https:\/\/github.com\/colbyfayock\/demo-image-upload-starter\">this Next.js Starter<\/a>, which creates a basic UI that will allow us to upload an image.<\/p>\n<p>You can do the same by running the command:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">yarn create next-app -e https:<span class=\"hljs-comment\">\/\/github.com\/colbyfayock\/demo-image-upload-starter my-image-background<\/span>\n<span class=\"hljs-comment\"># or<\/span>\nnpx create-next-app -e https:<span class=\"hljs-comment\">\/\/github.com\/colbyfayock\/demo-image-upload-starter my-image-background<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can then run the project locally by running:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">yarn dev\n<span class=\"hljs-comment\"># or<\/span>\nnpm run dev\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>When we select an image in the file-picker, we\u2019ll present that image on the page!<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/f_auto,q_auto\/c_limit,w_2000\/f_auto\/q_auto\/v1648822764\/e-61898aa20cfc9c0068be344d\/lwctpfu0f2feoi90gflf.png\" alt=\"Image uploader with my Twitter profile picture\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1120\"\/><\/p>\n<h2>Step 1: Installing and Configuring the Cloudinary Node SDK<\/h2>\n<p>We\u2019ll use the Cloudinary Node SDK to upload our images and change the background.<\/p>\n<p>First, let\u2019s install the SDK with:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">yarn add cloudinary\n<span class=\"hljs-comment\"># or<\/span>\nnpm install cloudinary\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we\u2019ll import v2 of the SDK into our project with:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">import { v2 <span class=\"hljs-keyword\">as<\/span> cloudinary } from <span class=\"hljs-string\">'cloudinary'<\/span>;\n<span class=\"hljs-comment\"># or<\/span>\n<span class=\"hljs-keyword\">const<\/span> cloudinary = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">'cloudinary'<\/span>).v2;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Finally, to configure the SDK, we\u2019ll need to configure our Cloudinary Cloud Name, API Key, and API Secret.<\/p>\n<p>I recommend setting up a local environment variables file to avoid committing your secret keys to your Git provider or when storing sensitive data in general.<\/p>\n<p>First, create a file in the root of your project called <code>.env.local<\/code> and add the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=\"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Your<\/span> <span class=\"hljs-attr\">Cloud<\/span> <span class=\"hljs-attr\">Name<\/span>&gt;<\/span>\"\nCLOUDINARY_API_KEY=\"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Your<\/span> <span class=\"hljs-attr\">API<\/span> <span class=\"hljs-attr\">Key<\/span>&gt;<\/span>\"\nCLOUDINARY_API_SECRET=\"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Your<\/span> <span class=\"hljs-attr\">API<\/span> <span class=\"hljs-attr\">Secret<\/span>&gt;<\/span>\"\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can find these values at the top of your Cloudinary dashboard.<\/p>\n<blockquote>\n<p>Note: We\u2019re prefixing the Cloud Name with NEXT_PUBLIC so that we can use that value in the client. Technically, we don\u2019t need to store this value in an environment variable, but since we\u2019re storing everything else, it makes it easier to manage from a single location.<\/p>\n<\/blockquote>\n<p>Now, when we go to use our SDK, those values will be available.<\/p>\n<p><a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/435028aad6bfe75382809fac8793b13245085897\">Follow along with the commit!<\/a><\/p>\n<h2>Step 2: Proxying Secure Upload and Resource Requests With Next.js Serverless Functions<\/h2>\n<p>To upload as a signed request and fetch our resource, which we\u2019ll need later, we should be able to use our credentials that we set up inside of <code>.env.local<\/code>.<\/p>\n<p>We\u2019ll use Next.js serverless functions, which give us a node environment where those values won\u2019t be exposed but are still useable.<\/p>\n<p>Navigating to the <code>pages\/api<\/code> directory, we can first add our Upload endpoint by creating a file called <code>upload.js<\/code>.<\/p>\n<p>Inside <code>pages\/api\/upload.js<\/code> add:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> cloudinary = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'cloudinary'<\/span>).v2;\n\ncloudinary.config({\n  <span class=\"hljs-attr\">cloud_name<\/span>: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,\n  <span class=\"hljs-attr\">api_key<\/span>: process.env.CLOUDINARY_API_KEY,\n  <span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET,\n  <span class=\"hljs-attr\">secure<\/span>: <span class=\"hljs-literal\">true<\/span>\n});\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handler<\/span>(<span class=\"hljs-params\">req, res<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> { image, options = {} } = <span class=\"hljs-built_in\">JSON<\/span>.parse(req.body);\n\n  <span class=\"hljs-keyword\">const<\/span> results = <span class=\"hljs-keyword\">await<\/span> cloudinary.uploader.upload(image, options);\n\n  res.status(<span class=\"hljs-number\">200<\/span>).json(results);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we\u2019ll:<\/p>\n<ul>\n<li>Import the Cloudinary SDK.<\/li>\n<li>Configure the Cloudinary SDK with our credentials.<\/li>\n<li>Create a new serverless function handler.<\/li>\n<li>Parse an image and options value from the request\u2019s body.<\/li>\n<li>Pass those values into the Cloudinary uploader.<\/li>\n<li>Return a 200 response with those results.<\/li>\n<\/ul>\n<p>This will make a new endpoint available at <code>\/api\/upload<\/code> that we\u2019ll be able to POST our uploads to.<\/p>\n<p>Next, we\u2019ll create another similar function to grab the details of a resource (like an image).<\/p>\n<p>Create a file called <code>resource.js<\/code> inside of <code>pages\/api<\/code> and inside of <code>pages\/api\/resource.js<\/code> add:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> cloudinary = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'cloudinary'<\/span>).v2;\n\ncloudinary.config({\n  <span class=\"hljs-attr\">cloud_name<\/span>: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,\n  <span class=\"hljs-attr\">api_key<\/span>: process.env.CLOUDINARY_API_KEY,\n  <span class=\"hljs-attr\">api_secret<\/span>: process.env.CLOUDINARY_API_SECRET,\n  <span class=\"hljs-attr\">secure<\/span>: <span class=\"hljs-literal\">true<\/span>,\n});\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handler<\/span>(<span class=\"hljs-params\">req, res<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> { publicId } = req.query || {};\n\n  <span class=\"hljs-keyword\">const<\/span> results = <span class=\"hljs-keyword\">await<\/span> cloudinary.api.resource(publicId);\n\n  res.status(<span class=\"hljs-number\">200<\/span>).json(results);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we\u2019ll:<\/p>\n<ul>\n<li>Import and configure Cloudinary.<\/li>\n<li>Create a new function where, this time, we\u2019ll grab a different data value from the query parameters.<\/li>\n<li>Pass that to the Cloudinary resource method.<\/li>\n<li>Return the response.<\/li>\n<\/ul>\n<p>Similar to our Upload endpoint, this will make a GET request available at <code>\/api\/resource?publicId=&lt;Public ID&gt;<\/code>.<\/p>\n<blockquote>\n<p>Note: There isn\u2019t really a distinct difference between POST and GET requests when creating the functions beyond how you accept the data where with POST we were using the body and GET we\u2019re using query parameters.<\/p>\n<\/blockquote>\n<p>Now that our endpoints are both set up, we\u2019ll be ready to get to work managing these assets in our app!<\/p>\n<p><a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/d611c9680311c473d5bb7f75a5617f192479d586\">Follow along with the commit!<\/a><\/p>\n<h2>Step 3: Uploading a Form Image to Cloudinary<\/h2>\n<p>In the app that we set up, we can use a form with a file-picker that will store our image in our local app\u2019s state.<\/p>\n<p>If you\u2019re following along, inside of our Starter in <code>pages\/index.js<\/code>, we can see it in this piece of code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> &#91;imageSrc, setImageSrc] = useState();\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleOnChange<\/span>(<span class=\"hljs-params\">changeEvent<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> reader = <span class=\"hljs-keyword\">new<\/span> FileReader();\n\n  reader.onload = <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span>(<span class=\"hljs-params\">onLoadEvent<\/span>) <\/span>{\n    setImageSrc(onLoadEvent.target.result);\n    setUploadData(<span class=\"hljs-literal\">undefined<\/span>);\n  }\n\n  reader.readAsDataURL(changeEvent.target.files&#91;<span class=\"hljs-number\">0<\/span>]);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We can see the value of the file-picker and store the data.<\/p>\n<p>With our Upload endpoint, we can now pass this right along using a POST request, which will tell Cloudinary that we want to upload that image and get a URL and its details in response.<\/p>\n<p>To do this, we have a Submit button hooked up to the <code>handleOnSubmit<\/code> function where we\u2019ll perform our upload.<\/p>\n<p>Update the <code>handleOnSubmit<\/code> function to:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">handleOnSubmit<\/span>(<span class=\"hljs-params\">event<\/span>) <\/span>{\n  event.preventDefault();\n\n  <span class=\"hljs-keyword\">const<\/span> results = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">'\/api\/upload'<\/span>, {\n    <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'POST'<\/span>,\n    <span class=\"hljs-attr\">body<\/span>: <span class=\"hljs-built_in\">JSON<\/span>.stringify({\n      <span class=\"hljs-attr\">image<\/span>: imageSrc\n    })\n  }).then(<span class=\"hljs-function\"><span class=\"hljs-params\">r<\/span> =&gt;<\/span> r.json());\n\n  setUploadData(results);\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we\u2019ll:<\/p>\n<ul>\n<li>Set up an async function.<\/li>\n<li>Prevent default to avoid the default browser actions for submitting a form.<\/li>\n<li>Pass along our image source to our API endpoint.<\/li>\n<li>Take the results and store it in a local state.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/f_auto,q_auto\/c_limit,w_2000\/f_auto\/q_auto\/v1648822549\/e-61898aa20cfc9c0068be344d\/qecrm8swbwfmqy9shkju.png\" alt=\"Cloudinary upload response\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"730\"\/><\/p>\n<p>Now, in our app, let\u2019s replace the locally selected image with our newly uploaded image.<\/p>\n<p>In our form, we\u2019ll see where we\u2019re adding the image using <code>imageSrc<\/code>. Let\u2019s replace that with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">{ imageSrc &amp;&amp; !uploadData &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{imageSrc}<\/span> \/&gt;<\/span>\n)}\n\n{ uploadData &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{uploadData.secure_url}<\/span> \/&gt;<\/span>\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>If we have an image source but no upload data, show the locally stored image. Otherwise, show the image we uploaded.<\/p>\n<p>At this point, you shouldn\u2019t even notice a difference, as the uploaded image should the same as the local image.<\/p>\n<p>But now we can kick off a separate request to remove our background.<\/p>\n<p><a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/ba61fbf589689b6ef9beba3f42e9c30c9ffd5be6\">Follow along with the commit!<\/a><\/p>\n<h2>Step 4: Removing the Background of an Image on Upload<\/h2>\n<p>In our last step, we uploaded our local image to Cloudinary, but now, we want to do the same thing <em>and<\/em> remove the background image.<\/p>\n<p>The tricky thing is this is an asynchronous process, where uploading the image kicks off the request, but then we need to keep checking until it\u2019s done in order to use it.<\/p>\n<p>To start, we\u2019ll utilize our existing upload, pass that URL to Cloudinary by telling it that we want to upload the same image, but remove the background.<\/p>\n<p>For this to work, you need to have the <a href=\"https:\/\/cloudinary.com\/documentation\/cloudinary_ai_background_removal_addon\">Cloudinary AI Background Removal add-on<\/a> installed on your Cloudinary account.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/f_auto,q_auto\/c_limit,w_2000\/f_auto\/q_auto\/v1648823322\/e-61898aa20cfc9c0068be344d\/sauesnmwetvlgutzd5za.png\" alt=\"Cloudinary AI Background Removal add-on\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"887\"\/><\/p>\n<blockquote>\n<p>Note: High usage costs money, but the free tier allows you to play around with it!<\/p>\n<\/blockquote>\n<p>But once we\u2019re ready to go, we\u2019ll use React\u2019s useEffect hook and say that whenever we have uploaded data available, we\u2019ll kick off a second request to upload.<\/p>\n<p>This will involve a few steps.<\/p>\n<p>First, let\u2019s import <code>useEffect<\/code> from React:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { useEffect, useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then, we\u2019ll want to store this transparent image upload separately, so let\u2019s set up a new instance of state:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> &#91;transparentData, setTransparentData] = useState();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In our page, we\u2019ll want to show our upload data and uploaded image, so under the <code>uploadData<\/code> add:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">{ uploadData &amp;&amp; !transparentData &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">pre<\/span>&gt;<\/span>Loading...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">pre<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span>\n)}\n\n{transparentData &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">code<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">pre<\/span>&gt;<\/span>{JSON.stringify(transparentData, null, 2)}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">pre<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">code<\/span>&gt;<\/span>\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We\u2019ll also add a check to see if our upload data is available, but not the transparent data, so that we have some kind of basic loading indicator.<\/p>\n<p>And finally, we\u2019ll want to perform the upload itself, so add the following under our transparentData state instance:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">if<\/span> ( !uploadData ) <span class=\"hljs-keyword\">return<\/span>;\n  (<span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">run<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n    <span class=\"hljs-keyword\">const<\/span> results = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">'\/api\/upload'<\/span>, {\n      <span class=\"hljs-attr\">method<\/span>: <span class=\"hljs-string\">'POST'<\/span>,\n      <span class=\"hljs-attr\">body<\/span>: <span class=\"hljs-built_in\">JSON<\/span>.stringify({\n        <span class=\"hljs-attr\">image<\/span>: uploadData.secure_url,\n        <span class=\"hljs-attr\">options<\/span>: {\n          <span class=\"hljs-attr\">background_removal<\/span>: <span class=\"hljs-string\">'cloudinary_ai'<\/span>\n        }\n      })\n    }).then(<span class=\"hljs-function\"><span class=\"hljs-params\">r<\/span> =&gt;<\/span> r.json());\n\n    <span class=\"hljs-keyword\">const<\/span> transparentResult = <span class=\"hljs-keyword\">await<\/span> checkStatus();\n\n    setTransparentData(transparentResult);\n\n    <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">checkStatus<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n      <span class=\"hljs-keyword\">const<\/span> resource = <span class=\"hljs-keyword\">await<\/span> fetch(<span class=\"hljs-string\">`\/api\/resource\/?publicId=<span class=\"hljs-subst\">${results.public_id}<\/span>`<\/span>).then(<span class=\"hljs-function\"><span class=\"hljs-params\">r<\/span> =&gt;<\/span> r.json());\n      <span class=\"hljs-keyword\">if<\/span> (resource.info.background_removal.cloudinary_ai.status === <span class=\"hljs-string\">'pending'<\/span>) {\n        <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>(<span class=\"hljs-function\">(<span class=\"hljs-params\">resolve<\/span>) =&gt;<\/span> setTimeout(resolve, <span class=\"hljs-number\">100<\/span>));\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">await<\/span> checkStatus();\n      }\n      <span class=\"hljs-keyword\">return<\/span> resource;\n    }\n  })();\n},&#91;uploadData, setTransparentData]);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is a big one, so let\u2019s break it down:<\/p>\n<ul>\n<li>We\u2019ll use useEffect and say that any time <code>uploadData<\/code> or our <code>setTransparentData<\/code> function changes, we want to fire it.<\/li>\n<li>First, make sure we have uploaded data before trying to use it.<\/li>\n<li>Then, we\u2019ll wrap everything in a self-invoking async function to allow us to use async\/await syntax (personal preference).<\/li>\n<li>In our async function, we\u2019ll fire our upload using the URL from our uploaded data.<\/li>\n<li>Additionally, we\u2019ll pass in an option that tells Cloudinary we want to use the <code>cloudinary_ai<\/code> background removal tool<\/li>\n<li>Once that\u2019s completed, we have our base image uploaded, but our background isn\u2019t removed, so we\u2019ll need to keep checking until it\u2019s complete, so\u2026<\/li>\n<li>We\u2019ll create a <code>checkStatus<\/code> function that recursively checks the resource status using our Resource endpoint.<\/li>\n<li>Once that endpoint returns the response that the removal was complete, it returns the resource.<\/li>\n<li>At which point, we\u2019ll store that transparent data locally.<\/li>\n<\/ul>\n<p>So after all of the above, we can now try to upload an image again, and if we patiently wait a few seconds after our first successful upload, we should see our uploaded data below our transparent data!<\/p>\n<p>We can even show that image instead of our original by replacing the image at the top:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">{ uploadData &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{transparentData?.secure_url<\/span> || <span class=\"hljs-attr\">uploadData.secure_url<\/span>} \/&gt;<\/span>\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>And we should now see it on the page!<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/f_auto,q_auto\/c_limit,w_2000\/f_auto\/q_auto\/v1648824287\/e-61898aa20cfc9c0068be344d\/qvxyvw3nh2eaxoqk6ubi.png\" alt=\"Background removed from my Twitter profile image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"950\"\/><\/p>\n<p><a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/536e5de8c0e750ef76357368175c9a36c7a8a837\">Follow along with the commit!<\/a><\/p>\n<h2>Step 5: Installing and Configuring the Cloudinary URL Gen SDK<\/h2>\n<p>At this point, we have our images uploaded to Cloudinary. However, we\u2019re currently just using the URLs \u201cas is.\u201d<\/p>\n<p>We want to be able to transform our image so that we can add some fun backgrounds.<\/p>\n<p>To do this, we\u2019ll use the Cloudinary URL Gen SDK, which will allow us to create our transformations in our React app, where the Node SDK is only available in Node (like our serverless function).<\/p>\n<p>First, let\u2019s install the URL Gen SDK with:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">yarn<\/span> <span class=\"hljs-selector-tag\">add<\/span> <span class=\"hljs-keyword\">@cloudinary<\/span>\/url-gen\n# <span class=\"hljs-keyword\">or<\/span>\nnpm install @cloudinary\/url-gen\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then, we can configure our SDK similarly to how we configured our Node SDK. However, this time, we just need to use the Cloud Name.<\/p>\n<blockquote>\n<p>Note: This is why we prefixed our Cloud Name with <code>NEXT_PUBLIC<\/code> earlier!<\/p>\n<\/blockquote>\n<p>At the top of <code>pages\/index.js<\/code> import the SDK:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { Cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@cloudinary\/url-gen'<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then, we can configure it with:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> cloudinary = <span class=\"hljs-keyword\">new<\/span> Cloudinary({\n  <span class=\"hljs-attr\">cloud<\/span>: {\n    <span class=\"hljs-attr\">cloudName<\/span>: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,\n  },\n  <span class=\"hljs-attr\">url<\/span>: {\n    <span class=\"hljs-attr\">secure<\/span>: <span class=\"hljs-literal\">true<\/span>,\n  },\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We can even set up our existing images to use the SDK to prepare ourselves to change the background.<\/p>\n<p>First, let\u2019s create our images:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> mainImage = uploadData &amp;&amp; cloudinary.image(uploadData.public_id).toURL();\n<span class=\"hljs-keyword\">const<\/span> transparentImage = transparentData &amp;&amp; cloudinary.image(transparentData.public_id).toURL()\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then, we can use them in the code:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">{ mainImage &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{transparentImage<\/span> || <span class=\"hljs-attr\">mainImage<\/span>} \/&gt;<\/span>\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>At this point, our pages and images should look exactly the same when loading and uploading, except for the URLs that are now generated using the Cloudinary URL Gen SDK!<\/p>\n<p><a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/d836e1812b775b07dac9beaa76b7073ea5289297\">Follow along with the commit!<\/a><\/p>\n<h2>Step 6: Changing the Background of Transparent Images Using Underlays<\/h2>\n<p>To change our background, we\u2019ll use a feature called underlays, meaning, we\u2019ll create a new layer <strong>underneath<\/strong> our base layer.<\/p>\n<p>This is opposite of overlays, where we would place it on top, but this allows us to easily set up an image behind our base image.<\/p>\n<p>To do this, we\u2019ll use images uploaded to our Cloudinary account, and specifically, we\u2019ll reference these images by Public ID.<\/p>\n<p>Before we dive in, find some images that you think will be fun backgrounds, and upload them to your Cloudinary account.<\/p>\n<blockquote>\n<p>Note: If you want to follow along, you can download the images I\u2019m using from GitHub: <a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/tree\/main\/public\/images\">https:\/\/github.com\/colbyfayock\/my-image-background\/tree\/main\/public\/images<\/a><\/p>\n<\/blockquote>\n<p>We\u2019ll want to collect all of the Public IDs of those images.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/f_auto,q_auto\/c_limit,w_2000\/f_auto\/q_auto\/v1648827978\/e-61898aa20cfc9c0068be344d\/noiog0osa5gyu8m04psq.png\" alt=\"Media Library with uploaded images and Public ID highlighted\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"819\"\/><\/p>\n<p>Next, we\u2019ll create an array with them to use in our app.<\/p>\n<p>For instance, mine using the IDs in the screenshot above would look like:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> BACKGROUNDS = &#91;\n  <span class=\"hljs-string\">'the-office_xvxmat'<\/span>,\n  <span class=\"hljs-string\">'moon-earth_rvkn3k'<\/span>,\n  <span class=\"hljs-string\">'this-is-fine_zfmbra'<\/span>,\n  <span class=\"hljs-string\">'mario_bmvvqb'<\/span>\n];\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then, we can use those backgrounds to create a thumbnail selection UI that will allow someone to select the background they want.<\/p>\n<p>Above our image, let\u2019s add some controls:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">{transparentImage &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>Backgrounds<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span>\n      <span class=\"hljs-attr\">display:<\/span> '<span class=\"hljs-attr\">flex<\/span>',\n      <span class=\"hljs-attr\">justifyContent:<\/span> '<span class=\"hljs-attr\">center<\/span>',\n      <span class=\"hljs-attr\">listStyle:<\/span> '<span class=\"hljs-attr\">none<\/span>',\n      <span class=\"hljs-attr\">margin:<\/span> <span class=\"hljs-attr\">0<\/span>,\n      <span class=\"hljs-attr\">padding:<\/span> <span class=\"hljs-attr\">0<\/span>,\n    }}&gt;<\/span>\n      {BACKGROUNDS.map(backgroundId =&gt; {\n        return (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{backgroundId}<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">margin:<\/span> '<span class=\"hljs-attr\">0<\/span> <span class=\"hljs-attr\">.5em<\/span>' }}&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n              <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span>\n                <span class=\"hljs-attr\">padding:<\/span> <span class=\"hljs-attr\">0<\/span>,\n                <span class=\"hljs-attr\">cursor:<\/span> '<span class=\"hljs-attr\">pointer<\/span>',\n                <span class=\"hljs-attr\">border:<\/span> <span class=\"hljs-attr\">background<\/span> === <span class=\"hljs-string\">backgroundId<\/span> ? '<span class=\"hljs-attr\">solid<\/span> <span class=\"hljs-attr\">3px<\/span> <span class=\"hljs-attr\">blueviolet<\/span>' <span class=\"hljs-attr\">:<\/span> <span class=\"hljs-attr\">0<\/span>\n              }}\n              <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> setBackground(backgroundId)}\n            &gt;\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span>\n                <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">display:<\/span> '<span class=\"hljs-attr\">block<\/span>' }}\n                <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{100}<\/span>\n                <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{cloudinary.image(backgroundId).resize(<\/span>'<span class=\"hljs-attr\">w_200<\/span>')<span class=\"hljs-attr\">.toURL<\/span>()}\n                <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"backgroundId\"<\/span>\n              \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n        )\n      })}\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/&gt;<\/span>\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<blockquote>\n<p>Note: I\u2019m just using some inline styles here to make it a little bit more usable.<\/p>\n<\/blockquote>\n<p>Here, we\u2019ll:<\/p>\n<ul>\n<li>Add a new section if we have a transparent image.<\/li>\n<li>Use an unordered list to list out each available background image.<\/li>\n<li>Set up the image URL with resizing using Cloudinary to deliver only the size we need for the thumbnail.<\/li>\n<li>Use an <code>onClick<\/code> handler to set the background ID whenever an image is selected.<\/li>\n<\/ul>\n<p>Now, because we\u2019re storing the active background ID in state, we\u2019ll need to create that new instance of state.<\/p>\n<p>At the top of the file, add:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> &#91;background, setBackground] = useState();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now that we have our background image, we can use it in our main image as a transformation.<\/p>\n<p>Let\u2019s create a new image variable:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">let<\/span> transformedImage;\n\n<span class=\"hljs-keyword\">if<\/span> ( transparentData &amp;&amp; background ) {\n  transformedImage = cloudinary.image(transparentData.public_id);\n\n  transformedImage.addTransformation(<span class=\"hljs-string\">`u_<span class=\"hljs-subst\">${background}<\/span>,c_fill,w_1.0,h_1.0,fl_relative`<\/span>);\n\n  transformedImage = transformedImage.toURL();\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we\u2019ll:<\/p>\n<ul>\n<li>Create a variable using let because we only want to define this under conditions, which are complicated, so we\u2019ll avoid doing it in a single line.<\/li>\n<li>We have transparent data and a background selected.<\/li>\n<li>Create a new image instance using our transparent image.<\/li>\n<li>Add a transformation of an underlay (<code>u<\/code>) where we use a crop of fill with a relative width and height set to <code>1.0<\/code> to allow us to make sure it just fills the background and doesn\u2019t resize the image<\/li>\n<li>Finally, turn it into a URL.<\/li>\n<\/ul>\n<p>To use this new image, we can simply tack it on to our existing image:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">{ mainImage &amp;&amp; (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{transformedImage<\/span> || <span class=\"hljs-attr\">transparentImage<\/span> || <span class=\"hljs-attr\">mainImage<\/span>} \/&gt;<\/span>\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Once we upload an image and select a background, we\u2019ll see our new image!<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/f_auto,q_auto\/c_limit,w_2000\/f_auto\/q_auto\/v1648829669\/e-61898aa20cfc9c0068be344d\/hiwj44ercjsm7dmvni3e.png\" alt=\"Mario background behind my Twitter profile image\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1083\"\/><\/p>\n<p><a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/8e2891968ad87246adb1822b6a9c014cb4987a31\">Follow along with the commit!<\/a><\/p>\n<h2>Bonus<\/h2>\n<p>In my demo at the top, you\u2019ll notice it\u2019s slightly different. Here are a few bonus additions to the project, not necessarily relevant to the tutorial, that will help clean things up a bit.<\/p>\n<ul>\n<li>\n<a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/9ddbb5f3cf04d11f744cf4a2f99d091fa987abd9\">Adding error handling<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/3d795ae9df7a4051fd73a41b66f45b9b1ab93c19\">UI styling and rearranging<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/github.com\/colbyfayock\/my-image-background\/commit\/edb715a3ca3733664ce622144f428b912914eef5\">Simple loading states<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":87,"featured_media":30424,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[332,370,177,212,383,246,380,386,373],"class_list":["post-27805","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-api","tag-image","tag-javascript","tag-next-js","tag-nodejs","tag-react","tag-serverless","tag-transform","tag-upload"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Change a Background With Cloudinary and Next.js<\/title>\n<meta name=\"description\" content=\"Remove the background from images and change to something else programmatically using Cloudinary AI.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Change a Background With Cloudinary and Next.js\" \/>\n<meta property=\"og:description\" content=\"Remove the background from images and change to something else programmatically using Cloudinary AI.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-07-14T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-05-03T22:13:45+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Change a Background With Cloudinary and Next.js\",\"datePublished\":\"2023-07-14T14:00:00+00:00\",\"dateModified\":\"2025-05-03T22:13:45+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA\",\"keywords\":[\"API\",\"Image\",\"Javascript\",\"Next.js\",\"Node(JS)\",\"React\",\"Serverless\",\"Transform\",\"Upload\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2023\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions\",\"url\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions\",\"name\":\"Change a Background With Cloudinary and Next.js\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA\",\"datePublished\":\"2023-07-14T14:00:00+00:00\",\"dateModified\":\"2025-05-03T22:13:45+00:00\",\"description\":\"Remove the background from images and change to something else programmatically using Cloudinary AI.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Change a Background With Cloudinary and Next.js\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Change a Background With Cloudinary and Next.js","description":"Remove the background from images and change to something else programmatically using Cloudinary AI.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions","og_locale":"en_US","og_type":"article","og_title":"Change a Background With Cloudinary and Next.js","og_description":"Remove the background from images and change to something else programmatically using Cloudinary AI.","og_url":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions","og_site_name":"Cloudinary Blog","article_published_time":"2023-07-14T14:00:00+00:00","article_modified_time":"2025-05-03T22:13:45+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs-png?_i=AA","type":"image\/png"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Change a Background With Cloudinary and Next.js","datePublished":"2023-07-14T14:00:00+00:00","dateModified":"2025-05-03T22:13:45+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA","keywords":["API","Image","Javascript","Next.js","Node(JS)","React","Serverless","Transform","Upload"],"inLanguage":"en-US","copyrightYear":"2023","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions","url":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions","name":"Change a Background With Cloudinary and Next.js","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA","datePublished":"2023-07-14T14:00:00+00:00","dateModified":"2025-05-03T22:13:45+00:00","description":"Remove the background from images and change to something else programmatically using Cloudinary AI.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/removing-and-changing-an-images-background-with-cloudinary-using-next-js-serverless-functions#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Change a Background With Cloudinary and Next.js"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1688152741\/Blog-background-removal-nextjs\/Blog-background-removal-nextjs.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27805","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=27805"}],"version-history":[{"count":10,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27805\/revisions"}],"predecessor-version":[{"id":37573,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27805\/revisions\/37573"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/30424"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27805"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27805"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27805"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}