Skip to content

How to build an Online Customizable-Anything Product Experience

We are in an era of rich media web experiences. A lot of new products, online shops, and apps give users more power & democratize specific actions that used to be performed by a select few and highly knowledgeable individuals.

Have you ever wondered how you can build or incorporate product-customization features into your app? Look no further!

In this article, I’ll walk you through how to leverage Cloudinary in rapidly building an online product customizable experience.

Head over to GitHub and clone the repository.

We use React and Node.js in the project. React for building out the upload and product customization features on the frontend and Node.js for uploading the images to Cloudinary on start up.

Now that you have it locally, please follow the instructions in the README page to run the app.

Once you have it running,

  • The images in the /images folder will be uploaded to your Cloudinary account via the Node.js server.

  • The app on your browser should look like so:


Currently, we have a book cover and a T-shirt. So let’s customize the book cover to our taste.

  • Select the book cover item

Select book

  • Change the color like so:

Change book color

  • Next, upload a different logo

Change logo

Here, you can see the upload modal with several options to upload an image.

We leverage the Cloudinary Upload Widget to perform uploads. It saves us a lot of time and provides a lot of options!

Upload modal

Once done, click on the next button to go to the next stage of customization:

Next stage of customization

  • Next, let’s customize the product by adding a text

Add a text

To download the customized product, you can click the next button to export the customized product.

Go ahead and customize the T-shirt. Then, play around with the features and explore.

You might be thinking–How do I add more products to customize asides from the two defaults? For Example, stickers, mugs, etc.

  • Add the images of the new products to the /images folder
  • Stop and run npm start again. – The images will be uploaded to Cloudinary once the command runs.
  • Open up src/ImagePicker.js, add a new block of code with the public_id of the new products that was uploaded. Next, invoke the AdvancedImage component to show the product on the page.


... const mug = new CloudinaryImage('mug', { cloudName: cloudName }, { analytics: false }) .resize(fit(50,50)) .effect(sharpen()); ... <div> <AdvancedImage cldImg={mug} onClick={()=> {props.mediaEditor.update({publicIds: [{publicId:'mug'}]})}}/> </div>
Code language: PHP (php)

You have explored how to go about the customizations in the step above. Let’s break down the code solution that made it possible.

One of the significant components of this app asides from the Upload Widget is the Cloudinary Media Editor Widget.

The Cloudinary Media Editor is an interactive user interface that provides common image editing actions to your users on your website or application. It requires only native JavaScript to integrate and eliminates the need to develop an in-house interactive media editor with just a few lines of code.

With this editor, you can reduce dependency on designers for simple recurring tasks. For example, with it, you edit media assets.


import React, { useState, useEffect } from 'react'; import './App.css'; import editorConfig from './config/editorConfig'; import ImagePicker from './ImagePicker'; import ColorPicker from "./ColorPicker"; import UploadLogo from "./UploadLogo"; /** * Launches mediaEditor * @param editor */ function launchEditor(editor){ editor.update(editorConfig);; } /** * Subscribes to "next", "prev", and "export" events * @param editor * @param setDisabled */ function editorListener(editor, setDisabled){ editor.on("next", (steps)=>{ if(steps.params.toStep === 'export'){ setDisabled(true); } }); editor.on("prev", (steps)=>{ if(steps.params.toStep !== 'export'){ setDisabled(false); } }); editor.on("export", ()=>{ setDisabled(false); // Resets transformation editor.update({image:{transformation: [{}]}});; }) } function App() { const [mediaEditor, setMediaEditor] = useState({}); const [disabled, setDisabled] = useState(false); useEffect(() => { const myEditor = window.cloudinary.mediaEditor({ appendTo: document.getElementById('widget') }); launchEditor(myEditor); editorListener(myEditor, setDisabled); setMediaEditor(myEditor); },[]); return ( <div> <div className="container" style={disabled ? {pointerEvents: "none", opacity: "0.4"} : {}}> <div> <ImagePicker mediaEditor={mediaEditor}/> </div> <div className="space"/> <UploadLogo mediaEditor={mediaEditor}/> <div className="space"/> <div> <ColorPicker mediaEditor={mediaEditor}/> </div> </div> <hr/> <div className='widget' id="widget" /> </div> ); } export default App;
Code language: JavaScript (javascript)

In the App.js file, you can see how we invoked it in the useEffect hook.

We could invoke it because we already required it in public/index.html like so:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <!-- manifest.json provides metadata used when your web app is added to the homescreen on Android. See --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link href="%PUBLIC_URL%/index.css" rel="stylesheet" /> <!-- Notice the use of %PUBLIC_URL% in the tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public` folder can be referenced from the HTML. Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> <title>React App</title> </head> <body> <div class="topnav"> <img src="cloudinary_icon.svg" width="30"/> Product Customization Sample App </div> <script src="" type="text/javascript"></script> <script src="" type="text/javascript"> </script> <noscript> You need to enable JavaScript to run this app. </noscript> <div id="root"></div> <!-- This HTML file is a template. If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> </body> </html>
Code language: HTML, XML (xml)

One way to easily achieve a customizable experience in your app is to enable a Cloudinary media editor workflow. To add Cloudinary’s Media Editor widget to your site:

  1. Include the JavaScript file:
  2. Initialize the Media Editor widget with the cloudinary.mediaEditor() method.
  3. Update the Media Editor configuration with the update(options) method.
  4. Show the Media Editor widget with the show() method.

Note: Ensure your cloudName and publicIds of the image are replaced with the appropriate values.

<script src="" type="text/javascript"></script>
const myEditor = cloudinary.mediaEditor();
  publicIds: ["sample"],
  cloudName: "demo"

Cloudinary provides a lot of options for product customization. For example, here is an excellent article on product customization via the product gallery widget.

With Cloudinary, you can automate your entire image-management lifecycle, from upload and transformation to optimization and delivery. The platform also features numerous capabilities for editing and managing videos.

Back to top

Featured Post