{"id":39801,"date":"2026-02-17T07:00:00","date_gmt":"2026-02-17T15:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=39801"},"modified":"2026-02-17T12:06:49","modified_gmt":"2026-02-17T20:06:49","slug":"context-aware-storefront-regional-personalization","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization","title":{"rendered":"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>We\u2019ve all done it: browsing the latest summer collection during a snowstorm, eyeing a heavy windbreaker staged in a bright, sunny studio while you\u2019re in the middle of a torrential downpour\u2026 For global brands, this creates a <strong>contextual disconnect<\/strong>, when the environment in the image doesn\u2019t match the user\u2019s reality, it feels generic and conversion rates can drop.<\/p>\n<p>Traditionally, this means a lot of manual work for designers to localize hundreds of assets.<\/p>\n<p>In this guide, you\u2019ll build the <strong>\u201cGlobal-Local\u201d Engine<\/strong>. By combining <strong>Next.js 16<\/strong>, <strong>Contentful<\/strong>, and <strong>Cloudinary\u2019s Generative AI<\/strong>, you\u2019ll create a self-adapting storefront that:<\/p>\n<ol>\n<li>Detects user context (location and weather) at the Edge.<\/li>\n<li>Orchestrates visual strategies via Contentful.<\/li>\n<li>Generates personalized backgrounds in real time using Cloudinary AI.<\/li>\n<\/ol>\n<p>The result is a storefront that feels like it was designed for the moment, no matter where the customer is in the world.<\/p>\n<ul>\n<li>\n<strong>Live Demo:<\/strong> <a href=\"https:\/\/seasonal-nomad.vercel.app\/\">seasonal-nomad.vercel.app<\/a>\n<\/li>\n<li>\n<strong>Source Code:<\/strong> <a href=\"https:\/\/github.com\/musebe\/seasonal-nomad\">github.com\/musebe\/seasonal-nomad<\/a>\n<\/li>\n<\/ul>\n<h2>The Architecture of Context<\/h2>\n<p>Your engine moves away from static assets toward a <strong>composable commerce<\/strong> stack. Instead of serving a prerendered image, you\u2019ll serve a dynamic instruction set.<\/p>\n<ul>\n<li>\n<strong>Next.js 16.<\/strong> You\u2019ll use the new <code>proxy.ts<\/code> model to intercept requests at the network boundary. It detects the user\u2019s environment and fetches real-time weather data before the HTML is even rendered, eliminating the \u201cflash\u201d of unstyled content.<\/li>\n<li>\n<strong>Contentful.<\/strong> This acts as your rules of engagement. Marketing teams can map weather codes (e.g., <code>Rain<\/code>, <code>Snow<\/code>) to descriptive AI prompts in the CMS, allowing them to update the site\u2019s visual strategy without touching a single line of code.<\/li>\n<li>\n<strong>Cloudinary.<\/strong> Using the latest <a href=\"https:\/\/www.contentful.com\/marketplace\/cloudinary\/\">Cloudinary Contentful integration<\/a>, the app pulls a master asset and applies the <code>replaceBackground<\/code> transformation. Generative AI renders a high-fidelity environment matching the user\u2019s atmosphere while optimizing delivery via <code>f_auto<\/code> and <code>q_auto<\/code>.<\/li>\n<\/ul>\n<h3>Contentful Structure<\/h3>\n<p>Before writing any code, structure your content using Contentful to ensure your Next.js frontend can query the right data at the right time.<\/p>\n<ol>\n<li>\n<strong>Define the content models.<\/strong> First, create two distinct models:<strong>Product<\/strong>, which includes fields for Name, Slug, and a JSON object for the Cloudinary media, and <strong>Weather Prompt<\/strong> (or Weather Settings), which uses a \u201cCondition\u201d field (e.g., \u201cRain\u201d) and an <code>aiPrompt<\/code> field.<\/li>\n<li>\n<strong>Populate the strategy.<\/strong> Create entries for common weather states: rain, clouds, and clear. For the \u201crain\u201d entry, make sure to provide a descriptive prompt: \u201ca moody rainy London street with puddles and soft street lamp reflections\u201d.<\/li>\n<li>\n<strong>Generate API keys.<\/strong> To allow the Next.js app to talk to your structured content, navigate to <strong>Settings &gt; API keys<\/strong> to generate a <strong>Space ID<\/strong> and a <strong>Content Delivery API (CDA) Access Token<\/strong>.<\/li>\n<\/ol>\n<h3>Cloudinary Integration<\/h3>\n<p>With the structure in place, you\u2019ll integrate Cloudinary directly into the Contentful workflow, so you can manage your assets without leaving the CMS.<\/p>\n<ol>\n<li>\n<strong>Configure the Cloudinary App.<\/strong> In Contentful, navigate to <strong>Apps &gt; Marketplace<\/strong> to install the Cloudinary Sidebar App. Configure it with the cloud name <code>demo-article-projects<\/code>, set the <strong>Starting folder<\/strong> to <code>seasonal-nomad<\/code> to isolate your assets, and enable <code>f_auto<\/code> and <code>q_auto<\/code> for global optimization.<\/li>\n<li>\n<strong>Link the JSON field.<\/strong> In the <strong>Product<\/strong> content model, set the <strong>Appearance<\/strong> of the <code>image<\/code> (JSON Object) field to use the Cloudinary App. This ensures that when you select an image, Contentful stores a rich JSON object containing the <code>public_id<\/code> and metadata instead of a simple URL string.<\/li>\n<li>\n<strong>Upload the master asset.<\/strong> Upload the \u201cApex Nomad\u201d jacket to the <code>seasonal-nomad<\/code> folder via the Contentful interface. The original image is a plain studio shot, so you can use generative AI to replace the background.<\/li>\n<\/ol>\n<h3>Next.js 16 Project Initialization<\/h3>\n<p>With your data sources (Contentful and Cloudinary) ready, you scaffolded the frontend using <strong>Next.js 16<\/strong> and <strong>Turbopack<\/strong>. This version of Next.js is optimized for speed through its new \u201cproxy\u201d architecture and improved caching.<\/p>\n<h3>Initializing the Next.js 16 Project<\/h3>\n<p>Start by scaffolding a modern Next.js 16 application. This command automatically sets up TypeScript, Tailwind CSS, and ESLint, giving us a production-ready starting point.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npx<\/span> <span class=\"hljs-selector-tag\">create-next-app<\/span><span class=\"hljs-keyword\">@latest<\/span> seasonal-nomad --typescript --tailwind --eslint\ncd seasonal-nomad\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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>Once inside, install your core UI and media dependencies. Use <strong>shadcn\/ui<\/strong> for accessible components and <strong>next-cloudinary<\/strong> to handle your AI transformations.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">next-cloudinary<\/span> <span class=\"hljs-selector-tag\">lucide-react<\/span>\n<span class=\"hljs-selector-tag\">npx<\/span> <span class=\"hljs-selector-tag\">shadcn<\/span><span class=\"hljs-keyword\">@latest<\/span> init\nnpx shadcn@latest add select skeleton\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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<h3>Configuring Environment Variables<\/h3>\n<p>To securely connect your Next.js application to Contentful and Cloudinary, you\u2019ll need to store your API credentials in an environment variable file. In the <strong>root directory<\/strong> of your project, create a new file named <code>.env.local<\/code> and add your keys:<\/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\"><span class=\"hljs-comment\"># Contentful Handshake<\/span>\nCONTENTFUL_SPACE_ID=<span class=\"hljs-string\">\"your_space_id\"<\/span>\nCONTENTFUL_ACCESS_TOKEN=<span class=\"hljs-string\">\"your_cda_token\"<\/span>\n\n<span class=\"hljs-comment\"># Cloudinary Creative Engine<\/span>\nNEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=<span class=\"hljs-string\">\"demo-article-projects\"<\/span>\n\n<span class=\"hljs-comment\"># Weather API<\/span>\nOPENWEATHER_API_KEY=<span class=\"hljs-string\">\"your_openweather_key\"<\/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\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h3>Project Directory Structure<\/h3>\n<p>We organized the project into a modular architecture to keep the fetching logic separated from the UI components.<\/p>\n<h3>The Contentful Client<\/h3>\n<p>To bridge the code with our CMS, first set up a dedicated client. This allows you to perform parallel data fetching, a key feature of Next.js 16 that lets you request the product and the weather prompt simultaneously to reduce load times.<\/p>\n<p>Install the Contentful delivery SDK, which provides the necessary methods to query your structured content.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm install contentful\n<\/code><\/span><\/pre>\n<p>Next, create a utility file, <code>lib\/contentful.ts<\/code>, that will serve as your single point of contact for CMS data. By using the Space ID and Access Token from <code>.env.local<\/code>, you\u2019ll establish a secure connection that only pulls \u201cMarket-Approved\u201d assets based on the unique slugs defined in Step 1.<\/p>\n<h3>The Parallel Fetcher Logic<\/h3>\n<p>In Next.js 16, performance is king. Instead of fetching the product and then waiting to fetch the weather prompt (a \u201cwaterfall\u201d), you\u2019ll trigger them at the same time using <code>Promise.all<\/code>. This ensures the \u201cGlobal-Local\u201d engine has all the data it needs to start rendering the moment the user hits the page.<\/p>\n<p><strong><code>lib\/contentful.ts<\/code><\/strong>:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" 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> { createClient } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'contentful'<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> client = createClient({\n  <span class=\"hljs-attr\">space<\/span>: process.env.CONTENTFUL_SPACE_ID!,\n  <span class=\"hljs-attr\">accessToken<\/span>: process.env.CONTENTFUL_ACCESS_TOKEN!,\n});\n\n<span class=\"hljs-comment\">\/**\n * Fetches a single product by its unique slug\n *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getProduct<\/span>(<span class=\"hljs-params\">slug: string<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> entries = <span class=\"hljs-keyword\">await<\/span> client.getEntries({ \n    <span class=\"hljs-attr\">content_type<\/span>: <span class=\"hljs-string\">'product'<\/span>, \n    <span class=\"hljs-string\">'fields.slug'<\/span>: slug \n  });\n  <span class=\"hljs-keyword\">return<\/span> entries.items&#91;<span class=\"hljs-number\">0<\/span>];\n}\n\n<span class=\"hljs-comment\">\/**\n * Maps the weather condition to a specific AI prompt\n *\/<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getWeatherPrompt<\/span>(<span class=\"hljs-params\">condition: string<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> entries = <span class=\"hljs-keyword\">await<\/span> client.getEntries({\n    <span class=\"hljs-attr\">content_type<\/span>: <span class=\"hljs-string\">'weatherSettings'<\/span>,\n    <span class=\"hljs-string\">'fields.condition'<\/span>: condition,\n  });\n  <span class=\"hljs-keyword\">return<\/span> entries.items&#91;<span class=\"hljs-number\">0<\/span>];\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><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>By structuring your client this way, you\u2019ll create a reusable \u201cfetcher\u201d that can handle any product or weather state without further code changes.<\/p>\n<blockquote>\n<p>View the full <code>lib\/contentful.ts<\/code> on <a href=\"https:\/\/github.com\/musebe\/seasonal-nomad\/blob\/main\/lib\/contentful.ts\">GitHub<\/a>.<\/p>\n<\/blockquote>\n<h3>The \u2018Edge\u2019 Personalization Logic (<code>proxy.ts<\/code>)<\/h3>\n<p>Next.js 16 is a more powerful <strong><code>proxy.ts<\/code><\/strong> model compared to traditional middleware. It acts as a high-performance interceptor that detects the user\u2019s environment at the network boundary, ensuring that personalization happens before the page even begins to render.<\/p>\n<h3>Intercepting the Request at the Edge<\/h3>\n<p>The proxy serves as the \u201csensing layer\u201d of our engine, and performs three critical tasks in a single pass:<\/p>\n<ol>\n<li>\n<strong>It captures the user\u2019s city via their IP address or a URL override<\/strong> from our <code>ContextSwitcher<\/code> dropdown.<\/li>\n<li>It communicates with the <strong>OpenWeatherMap API<\/strong> to retrieve current conditions (e.g., \u201crain\u201d, \u201csnow\u201d, \u201cclear\u201d).<\/li>\n<li>Instead of passing raw data, the proxy \u201cstamps\u201d the request with <strong>custom headers like <code>x-weather-condition<\/code> and <code>x-weather-temp<\/code><\/strong>.<\/li>\n<\/ol>\n<p>By doing this at the edge, you\u2019ll eliminate instances of when a page loads as one thing and then jumps to another once the browser\u2019s JavaScript kicks in.<\/p>\n<h3>Request Handshake<\/h3>\n<p>The core of this logic is the header, which provides the context that your server components will read to decide which AI prompt to fetch from Contentful.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ proxy.ts engine snippet<\/span>\n<span class=\"hljs-keyword\">const<\/span> weatherUrl = <span class=\"hljs-string\">`https:\/\/api.openweathermap.org\/data\/2.5\/weather?q=<span class=\"hljs-subst\">${city}<\/span>&amp;units=metric&amp;appid=<span class=\"hljs-subst\">${process.env.OPENWEATHER_API_KEY}<\/span>`<\/span>;\n<span class=\"hljs-keyword\">const<\/span> weatherRes = <span class=\"hljs-keyword\">await<\/span> fetch(weatherUrl);\n<span class=\"hljs-keyword\">const<\/span> data = <span class=\"hljs-keyword\">await<\/span> weatherRes.json();\n<span class=\"hljs-keyword\">const<\/span> condition = data.weather?.&#91;<span class=\"hljs-number\">0<\/span>]?.main || <span class=\"hljs-string\">'Clear'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Injecting the context into the request flow<\/span>\nresponse.headers.set(<span class=\"hljs-string\">'x-weather-condition'<\/span>, condition);\nresponse.headers.set(<span class=\"hljs-string\">'x-current-city'<\/span>, city);\nresponse.headers.set(<span class=\"hljs-string\">'x-weather-temp'<\/span>, <span class=\"hljs-built_in\">Math<\/span>.round(data.main?.temp || <span class=\"hljs-number\">0<\/span>).toString());\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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 setup ensures that by the time your main <code>page.tsx<\/code> starts executing, it already knows what the weather is like at the user\u2019s location.<\/p>\n<blockquote>\n<p>View the full proxy.ts on <a href=\"https:\/\/github.com\/musebe\/seasonal-nomad\/blob\/main\/proxy.ts\">GitHub<\/a>.<\/p>\n<\/blockquote>\n<h3>Building the Generative UI Boundary<\/h3>\n<p>Because the <code>next-cloudinary<\/code> component uses React state to manage complex AI background swaps, you must establish a <strong>client boundary<\/strong>. This separation ensures that the interactive creative engine of Cloudinary remains isolated from the data-heavy server components, keeping the initial page load lightweight.<\/p>\n<h3>The Creative Engine: <code>HeroMedia.tsx<\/code><\/h3>\n<p>The <code>HeroMedia<\/code> component is the visual heart of the storefront. It takes the context delivered by the proxy and the product data from Contentful to perform the final AI transformation.<\/p>\n<ul>\n<li>\n<strong>\u201cuse client\u201d directive.<\/strong> You\u2019ll mark this component to execute in the browser, allowing the Cloudinary library to handle the dynamic generation of the background based on the user\u2019s specific environment.<\/li>\n<li>\n<strong>The Generative AI trigger.<\/strong> Utilize the <code>replaceBackground<\/code> prop within the <code>CldImage<\/code> component. This prop sends the <code>aiPrompt<\/code> (fetched from Contentful) to Cloudinary\u2019s generative engine, which then swaps the original studio background for a contextually relevant one.<\/li>\n<li>\n<strong>Performance guardians.<\/strong> Resolve potential layout shifts and performance bottlenecks by implementing the <code>sizes<\/code> prop. This allows the browser to request the most efficient image dimensions for the current device, while the <code>priority<\/code> tag ensures the hero image is the first asset to load.<\/li>\n<\/ul>\n<h3>The Engine: Generative Transformation<\/h3>\n<p>The core of the UI logic is the integration of the <code>CldImage<\/code> component. By passing the dynamic prompt directly into the transformation engine, you\u2019ll achieve real-time personalization without manual asset management.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">\/\/ HeroMedia.tsx engine snippet\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CldImage<\/span>\n  <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{imagePublicId}<\/span>\n  <span class=\"hljs-attr\">fill<\/span>\n  \/* <span class=\"hljs-attr\">High-performance<\/span> <span class=\"hljs-attr\">responsive<\/span> <span class=\"hljs-attr\">media<\/span> <span class=\"hljs-attr\">delivery<\/span> *\/\n  <span class=\"hljs-attr\">sizes<\/span>=<span class=\"hljs-string\">\"(max-width: 768px) 100vw, 50vw\"<\/span>\n  <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{productName}<\/span>\n  \/* <span class=\"hljs-attr\">The<\/span> <span class=\"hljs-attr\">Generative<\/span> <span class=\"hljs-attr\">AI<\/span> <span class=\"hljs-attr\">Trigger<\/span> *\/\n  <span class=\"hljs-attr\">replaceBackground<\/span>=<span class=\"hljs-string\">{aiPrompt}<\/span> \n  <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"object-cover transition-transform duration-700 group-hover:scale-105\"<\/span>\n  <span class=\"hljs-attr\">priority<\/span>\n\/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><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>View full HeroMedia.tsx on <a href=\"https:\/\/github.com\/musebe\/seasonal-nomad\/blob\/main\/components\/home\/HeroMedia.tsx\">GitHub<\/a>.<\/p>\n<\/blockquote>\n<h3>Assembling the Final Storefront<\/h3>\n<p>The final step is the assembly of Contentful and Cloudinary within the main <strong><code>app\/page.tsx<\/code><\/strong>. This server component serves as the central hub, coordinating data from Contentful and the real-time context provided by our <code>proxy.ts<\/code>.<\/p>\n<ul>\n<li>\n<strong>Parallel data fetching.<\/strong> You\u2019ll utilize <code>Promise.all<\/code> to fetch the product details and the weather-based AI prompt simultaneously. This avoids a \u201cwaterfall\u201d effect, ensuring that the visual strategy and product data are ready at the same time.<\/li>\n<li>\n<strong>Reading context from headers.<\/strong> The page extracts the <code>x-weather-condition<\/code>, <code>x-weather-temp<\/code>, and <code>x-current-city<\/code> headers. These values determine exactly which AI background Cloudinary will generate and which statistics will appear in the UI.<\/li>\n<li>\n<strong>Loading states with suspense.<\/strong> Wrap the <code>HeroMedia<\/code> component in a <strong>React suspense<\/strong> boundary. This allows the textual content (like the product name and weather stats) to load instantly while the generative AI background replacement is being processed in the background.<\/li>\n<\/ul>\n<h3>The Engine: The Data Controller<\/h3>\n<p>The page logic bridges the gap between the raw environmental data from the proxy and the marketing strategy stored in Contentful.<\/p>\n<p>TypeScript<\/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-comment\">\/\/ app\/page.tsx engine snippet<\/span>\n<span class=\"hljs-keyword\">const<\/span> headerList = <span class=\"hljs-keyword\">await<\/span> headers();\n<span class=\"hljs-keyword\">const<\/span> currentCondition = headerList.get(<span class=\"hljs-string\">'x-weather-condition'<\/span>) || <span class=\"hljs-string\">'Clear'<\/span>;\n<span class=\"hljs-keyword\">const<\/span> temp = headerList.get(<span class=\"hljs-string\">'x-weather-temp'<\/span>) || <span class=\"hljs-string\">'--'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ Parallel fetch from the Contentful \"Brain\"<\/span>\n<span class=\"hljs-keyword\">const<\/span> &#91;product, weatherEntry] = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-built_in\">Promise<\/span>.all(&#91;\n  getProduct(<span class=\"hljs-string\">'apex-nomad-windbreaker'<\/span>),\n  getWeatherPrompt(currentCondition),\n]);\n\n<span class=\"hljs-comment\">\/\/ Extracting the AI prompt for Cloudinary<\/span>\n<span class=\"hljs-keyword\">const<\/span> aiPrompt = (weatherEntry?.fields.aiPrompt <span class=\"hljs-keyword\">as<\/span> string) || <span class=\"hljs-string\">'a high-tech showroom'<\/span>;\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<blockquote>\n<p>View full app\/page.tsx on <a href=\"https:\/\/github.com\/musebe\/seasonal-nomad\/blob\/main\/app\/page.tsx\">GitHub<\/a>.<\/p>\n<\/blockquote>\n<h3>The Final Result<\/h3>\n<p>When a user selects a city like <strong>Nairobi<\/strong>, the proxy detects \u201cclouds,\u201d the page will fetch the \u201ccloudy\u201d prompt from Contentful, and Cloudinary will render the jacket in a soft, overcast environment.<\/p>\n<h3>Performance and Optimization<\/h3>\n<p>In a high-fidelity storefront, performance is just as critical as the visuals. To ensure the user\u2019s experience feels premium and fast, you\u2019ll implement two critical optimization layers: <strong>UI stability<\/strong> and <strong>build integrity<\/strong>.<\/p>\n<h3>Handling the \u2018AI Wait\u2019 With Skeletons<\/h3>\n<p>Because Cloudinary\u2019s <code>replaceBackground<\/code> generates a new image dynamically, there\u2019s a brief processing window. Without a strategy, the page would \u201cjump\u201d as the image pops in, creating a jarring user experience. You\u2019ll solve this by using <strong>shadcn\/ui Skeletons<\/strong> wrapped in a React <code>Suspense<\/code> boundary. This gives the user immediate visual feedback and maintains layout stability while the generative AI works in the background.<\/p>\n<h3>Solving the Vercel \u2018Static Bailout\u2019 Error<\/h3>\n<p>One of the most common hurdles in Next.js 16 is static generation bailout. Since our <code>ContextSwitcher<\/code> uses the <code>useSearchParams()<\/code> hook to detect city changes, Next.js tries to opt the entire page into dynamic rendering.<\/p>\n<blockquote>\n<p><strong>The Fix: Suspense Boundary.<\/strong> Since you wrapped the search-dependent logic in a focused <code>Suspense<\/code> boundary within the <code>Navbar.tsx<\/code>, this isolated the dynamic behavior, allowing the rest of the site\u2019s layout to remain statically optimized and lightning-fast on Vercel.<\/p>\n<\/blockquote>\n<h3>The Engine: The Skeleton Implementation<\/h3>\n<p>Your implementation uses a dedicated skeleton that mimics the exact aspect ratio of your product media, ensuring zero layout shift.<\/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-comment\">\/\/ HeroSkeleton.tsx engine snippet<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">HeroSkeleton<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex items-center justify-center h-full w-full bg-slate-50 p-12\"<\/span>&gt;<\/span>\n      {\/* Aspect-ratio matching prevents layout shift *\/}\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Skeleton<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full max-w-md aspect-&#91;3\/4] bg-slate-200\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  )\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<blockquote>\n<p>View the full <code>HeroSkeleton.tsx<\/code> on <a href=\"https:\/\/github.com\/musebe\/seasonal-nomad\/blob\/main\/components\/home\/HeroSkeleton.tsx\">GitHub<\/a>.<\/p>\n<\/blockquote>\n<h2>Conclusion and GitHub Repository<\/h2>\n<p>By combining Contentful, Cloudinary, and the \u201cEdge\u201d orchestration of <strong>Next.js 16<\/strong>, you\u2019ve built a storefront that scales globally without taxing design resources. Instead of manual variations, generative AI handles the heavy lifting, ensuring every customer sees your products in an environment that actually matches the weather outside.<\/p>\n<ul>\n<li>\n<strong>Final Live Demo<\/strong>: <a href=\"https:\/\/seasonal-nomad.vercel.app\/\">seasonal-nomad.vercel.app<\/a>\n<\/li>\n<li>\n<strong>Full Source Code<\/strong>: <a href=\"https:\/\/github.com\/musebe\/seasonal-nomad\">github.com\/musebe\/seasonal-nomad<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":87,"featured_media":39802,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[98,409,212,366],"class_list":["post-39801","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-e-commerce","tag-generative-ai","tag-next-js","tag-personalization"],"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>Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js<\/title>\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\/context-aware-storefront-regional-personalization\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-17T15:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-17T20:06:49+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.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=\"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\/context-aware-storefront-regional-personalization#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js\",\"datePublished\":\"2026-02-17T15:00:00+00:00\",\"dateModified\":\"2026-02-17T20:06:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization\"},\"wordCount\":13,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA\",\"keywords\":[\"E-commerce\",\"Generative AI\",\"Next.js\",\"Personalization\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization\",\"url\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization\",\"name\":\"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA\",\"datePublished\":\"2026-02-17T15:00:00+00:00\",\"dateModified\":\"2026-02-17T20:06:49+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, 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":"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js","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\/context-aware-storefront-regional-personalization","og_locale":"en_US","og_type":"article","og_title":"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js","og_url":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization","og_site_name":"Cloudinary Blog","article_published_time":"2026-02-17T15:00:00+00:00","article_modified_time":"2026-02-17T20:06:49+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js","datePublished":"2026-02-17T15:00:00+00:00","dateModified":"2026-02-17T20:06:49+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization"},"wordCount":13,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA","keywords":["E-commerce","Generative AI","Next.js","Personalization"],"inLanguage":"en-US","copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization","url":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization","name":"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, Cloudinary, and Next.js","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA","datePublished":"2026-02-17T15:00:00+00:00","dateModified":"2026-02-17T20:06:49+00:00","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/context-aware-storefront-regional-personalization#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Building a Context-Aware Storefront: Automating Regional Personalization With Contentful, 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\/v1770932705\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js\/Blog_Building_a_Context-Aware_Storefront__Automating_Regional_Personalization_with_Contentful_Cloudinary_and_Next.js.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39801","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=39801"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39801\/revisions"}],"predecessor-version":[{"id":39804,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/39801\/revisions\/39804"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/39802"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=39801"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=39801"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=39801"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}