This workflow corresponds to n8n.io template #13751 — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "a6a8404f-b2cb-4889-b846-ef9019583595",
"name": "\ud83d\udccb Flow Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-800,
-368
],
"parameters": {
"width": 720,
"height": 556,
"content": "## \ud83d\uddbc\ufe0f Gemini Imagen 3 \u2013 Image Generation \u2192 Upload to URL\n\n**How it works:**\n1. Webhook receives a POST request with `jobType`: **localize** or **mockup**\n2. **Route by Job Type** switch sends it down the correct pipeline\n3. A code node crafts the ideal **Gemini Imagen 3 prompt** from the payload\n4. **Gemini Imagen 3** generates the image and returns it as base64\n5. A code node **decodes base64 \u2192 n8n binary** (mimeType `image/png`)\n6. The binary is handed to the **n8n Upload to URL node** which PUTs it to your CDN presigned URL\n7. A final code node builds the **JSON response** with the public CDN URL\n\n**Credential needed:**\n`Google AI Header Auth` \u2014 HTTP Header Auth\nHeader name: `x-goog-api-key` \u00b7 Value: `YOUR_GEMINI_API_KEY`\nGet your key at: aistudio.google.com\n\n**Two things to replace after import:**\n- `YOUR_CDN_PRESIGNED_PUT_URL` in both Upload to URL nodes\n- `YOUR_CDN_DOMAIN` in both response code nodes\n\n**Gemini Imagen 3 endpoint:**\n`POST https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-001:predict`\n\n"
},
"typeVersion": 1
},
{
"id": "dee009cf-b726-43ab-a744-779843852d31",
"name": "Sticky \u2013 Entry & Routing",
"type": "n8n-nodes-base.stickyNote",
"position": [
-64,
320
],
"parameters": {
"color": 7,
"width": 560,
"height": 668,
"content": "### 1\ufe0f\u20e3 Webhook Entry & Job Router\n**Webhook \u2013 Receive Image Job** accepts a POST at `/gemini-image-job` with `jobType` and generation parameters in the request body.\n**Route by Job Type Switch** reads `$json.body.jobType` and routes:\n- Output 0 `localize` \u2192 Localised Marketing Campaign pipeline\n- Output 1 `mockup` \u2192 Product Mockup pipeline\n- Fallback \u2192 **Respond \u2013 Error** node returns a 400 JSON error"
},
"typeVersion": 1
},
{
"id": "8e022129-2430-4209-bed9-9e13de95f776",
"name": "Sticky \u2013 Localize Pipeline",
"type": "n8n-nodes-base.stickyNote",
"position": [
576,
240
],
"parameters": {
"color": 7,
"width": 1504,
"height": 392,
"content": "### 2\ufe0f\u20e3 Localised Marketing Campaign\n**Build Localize Prompt** code node constructs the Imagen 3 prompt: recreate the master image with all embedded text accurately translated into `targetLanguage`, preserving original layout, fonts, brand colours and visual hierarchy. Injects `brandName` and `campaignText` from the payload. Also stamps a unique `jobId`.\n**Gemini Imagen 3 \u2013 Localize** POSTs to the Imagen 3 predict endpoint with `sampleCount: 1` and `aspectRatio: 1:1`. Returns `predictions[0].bytesBase64Encoded`.\n**Decode Localize Image** code node decodes the base64 string to a Buffer, writes it into the n8n binary store as property `data` with `mimeType: image/png` and filename `localized_{lang}_{jobId}.png`.\n**Upload to URL \u2013 Localize** is the **n8n built-in Upload to URL node** \u2014 it PUTs the binary to your CDN presigned URL with method PUT.\n**Build Localize Response** code node returns `{ success, jobId, language, publicUrl, generatedAt }`.\n**Respond to Webhook \u2013 Localize** sends the JSON back to the caller."
},
"typeVersion": 1
},
{
"id": "639f2425-b883-4a43-a1bd-fe8c03ee8861",
"name": "Sticky \u2013 Mockup Pipeline",
"type": "n8n-nodes-base.stickyNote",
"position": [
576,
672
],
"parameters": {
"color": 7,
"width": 1584,
"height": 332,
"content": "### 3\ufe0f\u20e3 High-Fidelity Product Mockup\n**Build Mockup Prompt** code node constructs the Imagen 3 prompt: photorealistic `productType` with the brand logo/pattern applied using `colorScheme`, studio lighting, natural fabric texture, realistic shadows. Stamps a unique `jobId`.\n**Gemini Imagen 3 \u2013 Mockup** POSTs to the same Imagen 3 endpoint. Returns the photorealistic product image as base64.\n**Decode Mockup Image** code node decodes base64 \u2192 binary, filename `mockup_{product}_{jobId}.png`.\n**Upload to URL \u2013 Mockup** is the **n8n built-in Upload to URL node** \u2014 PUTs the binary to your CDN presigned URL.\n**Build Mockup Response** code node returns `{ success, jobId, productType, colorScheme, publicUrl, generatedAt }`.\n**Respond to Webhook \u2013 Mockup** sends the JSON back to the caller."
},
"typeVersion": 1
},
{
"id": "b9681a8a-149d-4743-9e30-b1b9ac25c29c",
"name": "Webhook \u2013 Receive Image Job",
"type": "n8n-nodes-base.webhook",
"position": [
-32,
608
],
"parameters": {
"path": "gemini-image-job",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "7bdb63c2-e880-4ffd-8e00-010deec889a5",
"name": "Route by Job Type",
"type": "n8n-nodes-base.switch",
"position": [
320,
592
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Localize",
"conditions": {
"options": {
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.body.jobType.toLowerCase() }}",
"rightValue": "localize"
}
]
},
"renameOutput": true
},
{
"outputKey": "Mockup",
"conditions": {
"options": {
"caseSensitive": false,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.body.jobType.toLowerCase() }}",
"rightValue": "mockup"
}
]
},
"renameOutput": true
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"typeVersion": 3
},
{
"id": "5ecbbc02-0a8b-46e8-a2a2-ade5fa4f02f2",
"name": "Respond \u2013 Error",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
320,
800
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}"
},
"typeVersion": 1
},
{
"id": "25e9153d-88a4-44c0-ac84-13874e46583b",
"name": "Build Localize Prompt",
"type": "n8n-nodes-base.code",
"position": [
624,
432
],
"parameters": {
"jsCode": "const b = $json.body;\nconst lang = b.targetLanguage || 'Spanish';\nconst brand = b.brandName || 'Brand';\nconst text = b.campaignText || 'Special Offer';\nconst jobId = `LOC-${Date.now()}`;\n\nconst prompt = `Recreate this marketing image with all embedded text accurately translated into ${lang}. ` +\n `Preserve the exact original layout, visual hierarchy, font style and brand colours. ` +\n `Brand: ${brand}. Translated headline in ${lang}: \"${text}\". ` +\n `Photorealistic quality, sharp typography, professional marketing aesthetic, 1024x1024.`;\n\nreturn [{ json: { prompt, lang, brand, campaignText: text, jobId,\n masterImageUrl: b.masterImageUrl || '' } }];\n"
},
"typeVersion": 2
},
{
"id": "1ed05274-5d9d-488c-ba1c-3d495533d202",
"name": "Gemini Imagen 3 \u2013 Localize",
"type": "n8n-nodes-base.httpRequest",
"position": [
880,
432
],
"parameters": {
"url": "https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-001:predict",
"method": "POST",
"options": {},
"sendHeaders": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "1a22bb68-eea1-47eb-8ddc-05af39fd9ebf",
"name": "Decode Localize Image",
"type": "n8n-nodes-base.code",
"position": [
1152,
432
],
"parameters": {
"jsCode": "const pred = $json.predictions?.[0];\nif (!pred) throw new Error('Imagen 3 returned no prediction');\nconst b64 = pred.bytesBase64Encoded;\nconst mime = pred.mimeType || 'image/png';\nconst ext = mime.split('/')[1] || 'png';\nconst prev = $('Build Localize Prompt').item.json;\nconst fname = `localized_${prev.lang.toLowerCase().replace(/\\s+/g,'_')}_${prev.jobId}.${ext}`;\nconst buf = Buffer.from(b64, 'base64');\nreturn [{\n json: { ...prev, filename: fname, mimeType: mime },\n binary: { data: { data: b64, mimeType: mime, fileName: fname,\n fileSize: buf.length, fileExtension: ext } }\n}];\n"
},
"typeVersion": 2
},
{
"id": "e0281466-27cd-4873-b85e-165c864e41e0",
"name": "Build Localize Response",
"type": "n8n-nodes-base.code",
"position": [
1648,
432
],
"parameters": {
"jsCode": "const p = $('Build Localize Prompt').item.json;\nreturn [{ json: {\n success: true, jobId: p.jobId, jobType: 'localize',\n language: p.lang, brand: p.brand,\n filename: p.filename,\n publicUrl: `https://YOUR_CDN_DOMAIN/${p.filename}`,\n generatedAt: new Date().toISOString()\n}}];\n"
},
"typeVersion": 2
},
{
"id": "cf55d88e-88bc-4c3e-aa11-22017b1cc3f6",
"name": "Respond to Webhook \u2013 Localize",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1888,
432
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}"
},
"typeVersion": 1
},
{
"id": "71c6deda-bf19-4aff-87bc-be07f734d905",
"name": "Build Mockup Prompt",
"type": "n8n-nodes-base.code",
"position": [
624,
832
],
"parameters": {
"jsCode": "const b = $json.body;\nconst product = b.productType || 't-shirt';\nconst colors = b.colorScheme || 'navy and gold';\nconst logo = b.logoDescription || 'brand logo';\nconst jobId = `MKP-${Date.now()}`;\n\nconst prompt = `Photorealistic product mockup of a ${product}. ` +\n `Apply a ${logo} using ${colors} colour scheme. ` +\n `Studio background, professional lighting, natural fabric texture, realistic shadows and highlights. ` +\n `Premium commercial product photo ready for e-commerce. 1024x1024, no text overlays.`;\n\nreturn [{ json: { prompt, product, colors, logo, jobId } }];\n"
},
"typeVersion": 2
},
{
"id": "dddf4923-4fc0-453a-91d0-ad5ae7cd4d3e",
"name": "Gemini Imagen 3 \u2013 Mockup",
"type": "n8n-nodes-base.httpRequest",
"position": [
880,
832
],
"parameters": {
"url": "https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-001:predict",
"method": "POST",
"options": {},
"sendHeaders": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "93482732-f535-4118-89e6-36f0eaa87603",
"name": "Decode Mockup Image",
"type": "n8n-nodes-base.code",
"position": [
1152,
832
],
"parameters": {
"jsCode": "const pred = $json.predictions?.[0];\nif (!pred) throw new Error('Imagen 3 returned no prediction');\nconst b64 = pred.bytesBase64Encoded;\nconst mime = pred.mimeType || 'image/png';\nconst ext = mime.split('/')[1] || 'png';\nconst prev = $('Build Mockup Prompt').item.json;\nconst fname = `mockup_${prev.product.replace(/\\s+/g,'_')}_${prev.jobId}.${ext}`;\nconst buf = Buffer.from(b64, 'base64');\nreturn [{\n json: { ...prev, filename: fname, mimeType: mime },\n binary: { data: { data: b64, mimeType: mime, fileName: fname,\n fileSize: buf.length, fileExtension: ext } }\n}];\n"
},
"typeVersion": 2
},
{
"id": "d750be8f-048a-44f9-b0e4-26d279ddd93e",
"name": "Build Mockup Response",
"type": "n8n-nodes-base.code",
"position": [
1648,
832
],
"parameters": {
"jsCode": "const p = $('Build Mockup Prompt').item.json;\nreturn [{ json: {\n success: true, jobId: p.jobId, jobType: 'mockup',\n productType: p.product, colorScheme: p.colors,\n filename: p.filename,\n publicUrl: `https://YOUR_CDN_DOMAIN/${p.filename}`,\n generatedAt: new Date().toISOString()\n}}];\n"
},
"typeVersion": 2
},
{
"id": "4024e030-fe6a-4c63-a89f-5e4b28753eca",
"name": "Respond to Webhook \u2013 Mockup",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1888,
832
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ JSON.stringify($json) }}"
},
"typeVersion": 1
},
{
"id": "aed7cefc-af66-4a33-97ee-5aab1bd6d580",
"name": "Upload to URL",
"type": "n8n-nodes-uploadtourl.uploadToUrl",
"position": [
1392,
432
],
"parameters": {},
"credentials": {
"uploadToUrlApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "15704ba4-1042-46a6-9488-9b1dfd7cb46b",
"name": "Upload to URL1",
"type": "n8n-nodes-uploadtourl.uploadToUrl",
"position": [
1424,
832
],
"parameters": {},
"credentials": {
"uploadToUrlApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
}
],
"connections": {
"Upload to URL": {
"main": [
[
{
"node": "Build Localize Response",
"type": "main",
"index": 0
}
]
]
},
"Upload to URL1": {
"main": [
[
{
"node": "Build Mockup Response",
"type": "main",
"index": 0
}
]
]
},
"Route by Job Type": {
"main": [
[
{
"node": "Build Localize Prompt",
"type": "main",
"index": 0
}
],
[
{
"node": "Build Mockup Prompt",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond \u2013 Error",
"type": "main",
"index": 0
}
]
]
},
"Build Mockup Prompt": {
"main": [
[
{
"node": "Gemini Imagen 3 \u2013 Mockup",
"type": "main",
"index": 0
}
]
]
},
"Decode Mockup Image": {
"main": [
[
{
"node": "Upload to URL1",
"type": "main",
"index": 0
}
]
]
},
"Build Localize Prompt": {
"main": [
[
{
"node": "Gemini Imagen 3 \u2013 Localize",
"type": "main",
"index": 0
}
]
]
},
"Build Mockup Response": {
"main": [
[
{
"node": "Respond to Webhook \u2013 Mockup",
"type": "main",
"index": 0
}
]
]
},
"Decode Localize Image": {
"main": [
[
{
"node": "Upload to URL",
"type": "main",
"index": 0
}
]
]
},
"Build Localize Response": {
"main": [
[
{
"node": "Respond to Webhook \u2013 Localize",
"type": "main",
"index": 0
}
]
]
},
"Gemini Imagen 3 \u2013 Mockup": {
"main": [
[
{
"node": "Decode Mockup Image",
"type": "main",
"index": 0
}
]
]
},
"Gemini Imagen 3 \u2013 Localize": {
"main": [
[
{
"node": "Decode Localize Image",
"type": "main",
"index": 0
}
]
]
},
"Webhook \u2013 Receive Image Job": {
"main": [
[
{
"node": "Route by Job Type",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
httpHeaderAuthuploadToUrlApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Streamline your creative production with this high-performance image generation and hosting pipeline. This workflow automates the transition from raw creative prompts to hosted assets, leveraging Gemini Imagen 3 for photorealistic visual generation and an automated Upload to URL…
Source: https://n8n.io/workflows/13751/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Elevate your digital presence with high-fidelity cinematic video automation. This workflow orchestrates the complex, asynchronous rendering process of OpenAI Sora—transforming static product images or
Transform raw product images into fully-optimized e-commerce listings in seconds. This workflow automates the bridge between a photo upload and a live product page by combining UploadToURL for hosting
Schedule social media posts from local files using UploadToURL, OpenAI, and Buffer
Accelerate your real estate marketing by moving from "photo capture" to "published listing" in seconds. This workflow automates the entire listing process by hosting property photos via UploadToURL, u
This workflow automates end-to-end social media publishing powered by Late API. It generates text content with Google Gemini, creates branded visuals with Kie.ai, uploads media to Late, and publishes