{"id":26909,"date":"2023-02-23T08:00:00","date_gmt":"2023-02-23T15:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=26909"},"modified":"2025-09-30T07:42:33","modified_gmt":"2025-09-30T14:42:33","slug":"how-to-build-an-online-customizable-anything-product-experience","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience","title":{"rendered":"How to build an Online Customizable-Anything Product Experience using Cloudinary"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>We are in an era of rich media web experiences. A lot of new products, online shops, and apps give users more power &amp; democratize specific actions that used to be performed by a select few and highly knowledgeable individuals.<\/p>\n<p>Have you ever wondered how you can build or incorporate product-customization features into your app? Look no further!<\/p>\n<p>In this article, I\u2019ll walk you through how to leverage Cloudinary in rapidly building an online product customizable experience.<\/p>\n<h2>Getting Started<\/h2>\n<p>Head over to <a href=\"https:\/\/github.com\/cloudinary\/product-customization-sample-app\">GitHub<\/a> and clone the repository.<\/p>\n<p>We use <strong>React<\/strong> and <strong>Node.js<\/strong> 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 <em>start up<\/em>.<\/p>\n<p>Now that you have it locally, please follow the instructions <a href=\"https:\/\/github.com\/cloudinary\/product-customization-sample-app#getting-started\">in the README page to run the app.<\/a><\/p>\n<h2>Product Customization<\/h2>\n<p>Once you have it running,<\/p>\n<ul>\n<li>\n<p>The images in the <em>\/images<\/em> folder will be uploaded to your Cloudinary account via the Node.js server.<\/p>\n<\/li>\n<li>\n<p>The app on your browser should look like so:<\/p>\n<\/li>\n<\/ul>\n<p>Currently, we have a book cover and a T-shirt. So let\u2019s customize the book cover to our taste.<\/p>\n<ul>\n<li>\n<p>Select the book cover item<\/p>\n<\/li>\n<li>\n<p>Change the color like so:<\/p>\n<\/li>\n<li>\n<p>Next, upload a different logo<\/p>\n<\/li>\n<\/ul>\n<p>Here, you can see the upload modal with several options to upload an image.<\/p>\n<p>We leverage the <a href=\"https:\/\/cloudinary.com\/documentation\/upload_widget\">Cloudinary Upload Widget<\/a> to perform uploads. It saves us a lot of time and provides a lot of options!<\/p>\n<p>Once done, click on the next button to go to the next stage of customization:<\/p>\n<ul>\n<li>Next, let\u2019s customize the product by adding a text<\/li>\n<\/ul>\n<p>To download the customized product, you can click the next button to export the customized product.<\/p>\n<h3>Next Steps for Customization<\/h3>\n<p>Go ahead and customize the T-shirt. Then, play around with the features and explore.<\/p>\n<p>You might be thinking\u2013<strong>How do I add more products to customize asides from the two defaults?<\/strong> For Example, stickers, mugs, etc.<\/p>\n<ul>\n<li>Add the images of the new products to the <code>\/images<\/code> folder<\/li>\n<li>Stop and run <code>npm start<\/code> again. &#8211; <em>The images will be uploaded to Cloudinary once the command runs<\/em>.<\/li>\n<li>Open up <em>src\/ImagePicker.js<\/em>, 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.<\/li>\n<\/ul>\n<p><strong>Example:<\/strong><\/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\">...\n<span class=\"hljs-keyword\">const<\/span> mug = <span class=\"hljs-keyword\">new<\/span> CloudinaryImage(<span class=\"hljs-string\">'mug'<\/span>, { cloudName: cloudName }, { analytics: <span class=\"hljs-keyword\">false<\/span> })\n  .resize(fit(<span class=\"hljs-number\">50<\/span>,<span class=\"hljs-number\">50<\/span>))\n  .effect(sharpen());\n\n...\n&lt;div&gt;\n        &lt;AdvancedImage cldImg={mug} onClick={()=&gt; {props.mediaEditor.update({publicIds: &#91;{publicId:<span class=\"hljs-string\">'mug'<\/span>}]})}}\/&gt;\n&lt;\/div&gt;\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<h2>Product Customization Code Analysis<\/h2>\n<p>You have explored how to go about the customizations in the step above. Let\u2019s break down the code solution that made it possible.<\/p>\n<p>One of the significant components of this app asides from the <a href=\"https:\/\/cloudinary.com\/documentation\/upload_widget\">Upload Widget<\/a> is the <a href=\"https:\/\/cloudinary.com\/documentation\/media_editor\">Cloudinary Media Editor Widget<\/a>.<\/p>\n<p>The <strong>Cloudinary Media Editor<\/strong> 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.<\/p>\n<p>With this editor, you can reduce dependency on designers for simple recurring tasks. For example, with it, you edit media assets.<\/p>\n<p><em>App.js<\/em><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" 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> React, { useState, useEffect } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'.\/App.css'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> editorConfig <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/config\/editorConfig'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> ImagePicker <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/ImagePicker'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> ColorPicker <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/ColorPicker\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> UploadLogo <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/UploadLogo\"<\/span>;\n\n<span class=\"hljs-comment\">\/**\n * Launches mediaEditor\n * @param editor\n *\/<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">launchEditor<\/span>(<span class=\"hljs-params\">editor<\/span>)<\/span>{\n  editor.update(editorConfig);\n  editor.show();\n}\n\n<span class=\"hljs-comment\">\/**\n * Subscribes to \"next\", \"prev\", and \"export\" events\n * <span class=\"hljs-doctag\">@param <span class=\"hljs-variable\">editor<\/span><\/span>\n * <span class=\"hljs-doctag\">@param <span class=\"hljs-variable\">setDisabled<\/span><\/span>\n *\/<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">editorListener<\/span>(<span class=\"hljs-params\">editor, setDisabled<\/span>)<\/span>{\n  editor.on(<span class=\"hljs-string\">\"next\"<\/span>, (steps)=&gt;{\n    <span class=\"hljs-keyword\">if<\/span>(steps.params.toStep === <span class=\"hljs-string\">'export'<\/span>){\n      setDisabled(<span class=\"hljs-literal\">true<\/span>);\n    }\n  });\n  editor.on(<span class=\"hljs-string\">\"prev\"<\/span>, (steps)=&gt;{\n    <span class=\"hljs-keyword\">if<\/span>(steps.params.toStep !== <span class=\"hljs-string\">'export'<\/span>){\n      setDisabled(<span class=\"hljs-literal\">false<\/span>);\n    }\n  });\n  editor.on(<span class=\"hljs-string\">\"export\"<\/span>, ()=&gt;{\n    setDisabled(<span class=\"hljs-literal\">false<\/span>);\n\n    <span class=\"hljs-comment\">\/\/ Resets transformation<\/span>\n    editor.update({<span class=\"hljs-attr\">image<\/span>:{<span class=\"hljs-attr\">transformation<\/span>: &#91;{}]}});\n    editor.show();\n  })\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#91;mediaEditor, setMediaEditor] = useState({});\n  <span class=\"hljs-keyword\">const<\/span> &#91;disabled, setDisabled] = useState(<span class=\"hljs-literal\">false<\/span>);\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> myEditor = <span class=\"hljs-built_in\">window<\/span>.cloudinary.mediaEditor({ <span class=\"hljs-attr\">appendTo<\/span>: <span class=\"hljs-built_in\">document<\/span>.getElementById(<span class=\"hljs-string\">'widget'<\/span>) });\n    launchEditor(myEditor);\n    editorListener(myEditor, setDisabled);\n    setMediaEditor(myEditor);\n\n  },&#91;]);\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"container\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{disabled<\/span> ? {<span class=\"hljs-attr\">pointerEvents:<\/span> \"<span class=\"hljs-attr\">none<\/span>\", <span class=\"hljs-attr\">opacity:<\/span> \"<span class=\"hljs-attr\">0.4<\/span>\"} <span class=\"hljs-attr\">:<\/span> {}}&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ImagePicker<\/span> <span class=\"hljs-attr\">mediaEditor<\/span>=<span class=\"hljs-string\">{mediaEditor}\/<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"space\"<\/span>\/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">UploadLogo<\/span> <span class=\"hljs-attr\">mediaEditor<\/span>=<span class=\"hljs-string\">{mediaEditor}\/<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"space\"<\/span>\/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ColorPicker<\/span> <span class=\"hljs-attr\">mediaEditor<\/span>=<span class=\"hljs-string\">{mediaEditor}\/<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">hr<\/span>\/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">'widget'<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"widget\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> App;\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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 the <em>App.js<\/em> file, you can see how we invoked it in the useEffect hook.<\/p>\n<p>We could invoke it because we already required it in <em>public\/index.html<\/em> like so:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-meta\">&lt;!DOCTYPE <span class=\"hljs-meta-keyword\">html<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"en\"<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">charset<\/span>=<span class=\"hljs-string\">\"utf-8\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">link<\/span> <span class=\"hljs-attr\">rel<\/span>=<span class=\"hljs-string\">\"shortcut icon\"<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"%PUBLIC_URL%\/favicon.ico\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"viewport\"<\/span> <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">\"width=device-width, initial-scale=1, shrink-to-fit=no\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"theme-color\"<\/span> <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">\"#000000\"<\/span>&gt;<\/span>\n  <span class=\"hljs-comment\">&lt;!--\n      manifest.json provides metadata used when your web app is added to the\n      homescreen on Android. See https:\/\/developers.google.com\/web\/fundamentals\/engage-and-retain\/web-app-manifest\/\n    --&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">link<\/span> <span class=\"hljs-attr\">rel<\/span>=<span class=\"hljs-string\">\"manifest\"<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"%PUBLIC_URL%\/manifest.json\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">link<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"%PUBLIC_URL%\/index.css\"<\/span> <span class=\"hljs-attr\">rel<\/span>=<span class=\"hljs-string\">\"stylesheet\"<\/span> \/&gt;<\/span>\n\n  <span class=\"hljs-comment\">&lt;!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"\/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%\/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    --&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>React App<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"topnav\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"cloudinary_icon.svg\"<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"30\"<\/span>\/&gt;<\/span>\n  Product Customization Sample App\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/media-editor.cloudinary.com\/all.js\"<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\/javascript\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/upload-widget.cloudinary.com\/global\/all.js\"<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\/javascript\"<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">noscript<\/span>&gt;<\/span>\n    You need to enable JavaScript to run this app.\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">noscript<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"root\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n  <span class=\"hljs-comment\">&lt;!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the &lt;body&gt; tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><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<h2>The Cloudinary Product Customization Experience<\/h2>\n<p>One way to easily achieve a customizable experience in your app is to enable a Cloudinary media editor workflow. To add Cloudinary\u2019s Media Editor widget to your site:<\/p>\n<ol>\n<li>Include the JavaScript file: <a href=\"https:\/\/media-editor.cloudinary.com\/all.js.\">https:\/\/media-editor.cloudinary.com\/all.js.<\/a>\n<\/li>\n<li>Initialize the <em>Media Editor widget<\/em> with the <code>cloudinary.mediaEditor()<\/code> method.<\/li>\n<li>Update the Media Editor configuration with the <code>update(options)<\/code> method.<\/li>\n<li>Show the Media Editor widget with the <code>show()<\/code> method.<\/li>\n<\/ol>\n<p><strong>Note:<\/strong> Ensure your <code>cloudName<\/code> and <code>publicIds<\/code> of the image are replaced with the appropriate values.<\/p>\n<pre class=\"js-syntax-highlighted\"><code>&lt;script src=&quot;https:\/\/media-editor.cloudinary.com\/all.js&quot; type=&quot;text\/javascript&quot;&gt;&lt;\/script&gt;\n&lt;script&gt;\nconst myEditor = cloudinary.mediaEditor();\nmyEditor.update({\n  publicIds: [&quot;sample&quot;],\n  cloudName: &quot;demo&quot;\n});\nmyEditor.show();\nmyEditor.on(&quot;export&quot;,function(data){\n  console.log(data);\n})\n&lt;\/script&gt;\n<\/code><\/pre>\n<h2>Conclusion<\/h2>\n<p>Cloudinary provides a lot of options for product customization. For example, here is an <a href=\"https:\/\/cloudinary.com\/blog\/product-customization-with-cloudinary\">excellent article on product customization via the product gallery widget<\/a>.<\/p>\n<p>With Cloudinary, you can automate your entire image-management lifecycle, from <a href=\"https:\/\/cloudinary.com\/documentation\/image_transformations\">upload and transformation<\/a> to <a href=\"https:\/\/cloudinary.com\/documentation\/image_delivery_options\">optimization and delivery<\/a>. The platform also features numerous capabilities for editing and managing videos.<\/p>\n<\/div>\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":54,"featured_media":26914,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[98],"class_list":["post-26909","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-e-commerce"],"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>How to build an Online Customizable-Anything Product Experience using Cloudinary<\/title>\n<meta name=\"description\" content=\"Learn how you can build and embed product customization features into your web application using Cloudinary.\" \/>\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\/how-to-build-an-online-customizable-anything-product-experience\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to build an Online Customizable-Anything Product Experience using Cloudinary\" \/>\n<meta property=\"og:description\" content=\"Learn how you can build and embed product customization features into your web application using Cloudinary.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-02-23T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-09-30T14:42:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_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\/jpeg\" \/>\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\/how-to-build-an-online-customizable-anything-product-experience#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"How to build an Online Customizable-Anything Product Experience using Cloudinary\",\"datePublished\":\"2023-02-23T15:00:00+00:00\",\"dateModified\":\"2025-09-30T14:42:33+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience\"},\"wordCount\":10,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA\",\"keywords\":[\"E-commerce\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2023\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience\",\"url\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience\",\"name\":\"How to build an Online Customizable-Anything Product Experience using Cloudinary\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA\",\"datePublished\":\"2023-02-23T15:00:00+00:00\",\"dateModified\":\"2025-09-30T14:42:33+00:00\",\"description\":\"Learn how you can build and embed product customization features into your web application using Cloudinary.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to build an Online Customizable-Anything Product Experience using Cloudinary\"}]},{\"@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\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to build an Online Customizable-Anything Product Experience using Cloudinary","description":"Learn how you can build and embed product customization features into your web application using Cloudinary.","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\/how-to-build-an-online-customizable-anything-product-experience","og_locale":"en_US","og_type":"article","og_title":"How to build an Online Customizable-Anything Product Experience using Cloudinary","og_description":"Learn how you can build and embed product customization features into your web application using Cloudinary.","og_url":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience","og_site_name":"Cloudinary Blog","article_published_time":"2023-02-23T15:00:00+00:00","article_modified_time":"2025-09-30T14:42:33+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience"},"author":{"name":"","@id":""},"headline":"How to build an Online Customizable-Anything Product Experience using Cloudinary","datePublished":"2023-02-23T15:00:00+00:00","dateModified":"2025-09-30T14:42:33+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience"},"wordCount":10,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA","keywords":["E-commerce"],"inLanguage":"en-US","copyrightYear":"2023","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience","url":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience","name":"How to build an Online Customizable-Anything Product Experience using Cloudinary","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA","datePublished":"2023-02-23T15:00:00+00:00","dateModified":"2025-09-30T14:42:33+00:00","description":"Learn how you can build and embed product customization features into your web application using Cloudinary.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/how-to-build-an-online-customizable-anything-product-experience#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to build an Online Customizable-Anything Product Experience using Cloudinary"}]},{"@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":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1675196987\/blog-product_customization\/blog-product_customization.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/26909","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\/54"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=26909"}],"version-history":[{"count":14,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/26909\/revisions"}],"predecessor-version":[{"id":38670,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/26909\/revisions\/38670"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/26914"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=26909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=26909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=26909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}