This workflow corresponds to n8n.io template #15405 — we link there as the canonical source.
This workflow follows the Agent → Form Trigger recipe pattern — see all workflows that pair these two integrations.
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 →
{
"id": "",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Generate AI Ecommerce Ads from Website and Images with Claude + NanoBanana",
"tags": [],
"nodes": [
{
"id": "c42e99fd-eb43-4610-8bb9-22c0df50a41a",
"name": "Text extract",
"type": "n8n-nodes-base.markdown",
"position": [
-1680,
800
],
"parameters": {
"html": "={{ $('Fetch Homepage').item.json.data }}",
"options": {
"ignore": "a,img"
}
},
"typeVersion": 1
},
{
"id": "758b1e72-3d9f-4459-bfae-a54925c26664",
"name": "Aggregate1",
"type": "n8n-nodes-base.aggregate",
"position": [
-1488,
800
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "data"
}
]
}
},
"typeVersion": 1
},
{
"id": "59b61e40-6514-4aa7-a4f7-c7a1b4ff9fa0",
"name": "Upload file",
"type": "n8n-nodes-base.googleDrive",
"position": [
-2416,
1408
],
"parameters": {
"name": "=",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "1y2AK8wejMF8q_l9d3HH5oZiRfWx3fHey",
"cachedResultUrl": "https://drive.google.com/drive/folders/1y2AK8wejMF8q_l9d3HH5oZiRfWx3fHey",
"cachedResultName": "n8n"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "c97a1571-ad8c-4044-860f-b22189612b04",
"name": "Structured Output Parser2",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-3296,
1648
],
"parameters": {
"jsonSchemaExample": "{\n \"copy_structure\": \"\",\n \"primary_text\": \"\",\n \"secondary_text\": \"\",\n \"microcopy_elements\": [],\n \"cta_text\": \"\",\n \"creative_idea\": \"\",\n \"main_visual\": \"\",\n \"layout_description\": \"\",\n \"style_direction\": \"\"\n}"
},
"typeVersion": 1.3
},
{
"id": "081d7753-0f1a-4f3c-bad1-60e9cfab0eb8",
"name": "Anthropic Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
-3424,
1648
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-5-20250929",
"cachedResultName": "Claude Sonnet 4.5"
},
"options": {}
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "be4f5251-bd6c-4d08-8763-1466584623cc",
"name": "Convert to File2",
"type": "n8n-nodes-base.convertToFile",
"onError": "continueErrorOutput",
"position": [
-2640,
1424
],
"parameters": {
"options": {},
"operation": "toBinary",
"sourceProperty": "outputfile"
},
"typeVersion": 1.1
},
{
"id": "f3bb2342-f577-478b-871d-3a2b3356aed8",
"name": "set outputfile",
"type": "n8n-nodes-base.set",
"position": [
-2864,
1424
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "84544a25-271b-4c63-ade5-06af10150d12",
"name": "outputfile",
"type": "string",
"value": "={{ $json.choices[0].message.images[0].image_url.url.split(\",\")[1] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "554b8e15-b250-43d4-8840-a787dc44ae18",
"name": "Anthropic Chat Model3",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
-3776,
1648
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-5-20250929",
"cachedResultName": "Claude Sonnet 4.5"
},
"options": {}
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "47936971-0fd3-4ec4-a187-85ff6cfff538",
"name": "Structured Output Parser3",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-3648,
1648
],
"parameters": {
"jsonSchemaExample": "{\n \"product_name\": \"\",\n \"product_summary\": \"\",\n \"product_category\": \"\",\n \"customer_group\": \"\",\n \"use_cases\": [],\n \"problems_needs\": [],\n \"solution\": \"\",\n \"key_product_features\": [],\n \"key_benefits\": [],\n \"proof_trust_signals\": [],\n \"offer_pricing\": \"\",\n \"brand_voice\": \"\",\n \"marketing_brief\": \"\",\n \"business_type\": \"Ecommerce\"\n}"
},
"typeVersion": 1.3
},
{
"id": "8ac10e1a-ff07-43a4-b5b6-e564bb297ba7",
"name": "User Asset Base64",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-2976,
720
],
"parameters": {
"options": {},
"operation": "binaryToPropery",
"destinationKey": "Logo",
"binaryPropertyName": "=data"
},
"typeVersion": 1
},
{
"id": "54f02331-035b-466e-b6d2-0cd1f10c6cae",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
-3344,
736
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "16bc796d-fbdc-49b9-b080-21cd6a4eb46f",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.binary_field_name }}",
"rightValue": "Logo"
}
]
}
},
"typeVersion": 2.3
},
{
"id": "854bc1e1-87da-4e61-ae50-5e48c5fece73",
"name": "User Asset Base",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-3200,
864
],
"parameters": {
"options": {},
"operation": "binaryToPropery",
"binaryPropertyName": "=data"
},
"typeVersion": 1
},
{
"id": "d9afa614-9de5-460a-ab9e-01b6b5c0af26",
"name": "Call Claude - Photo Evaluation",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"maxTries": 2,
"position": [
-2976,
864
],
"parameters": {
"url": "https://openrouter.ai/api/v1/chat/completions",
"method": "POST",
"options": {},
"jsonBody": "={\n \"model\": \"anthropic/claude-sonnet-4.5\",\n \"temperature\": 0,\n \"response_format\": {\n \"type\": \"json_object\"\n },\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": \"Analyze the provided Product_photo and classify what it is. Return strict JSON only with this structure: {\\\"category\\\":\\\"\\\",\\\"confidence\\\":\\\"\\\",\\\"description\\\":\\\"\\\",\\\"is_ui\\\":false,\\\"is_person\\\":false,\\\"is_product\\\":false,\\\"is_packaging\\\":false,\\\"is_illustration\\\":false}. Choose category from exactly one of: person, product, packaging, ui, dashboard, object, icon, illustration, abstract_graphic, scene, other. Base the answer only on the image. Do not guess the brand or business context.\"\n },\n {\n \"type\": \"image_url\",\n \"image_url\": {\n \"url\": \"data:{{ $('Split Uploaded Files').item.binary.data.mimeType || 'image/png' }};base64,{{ $json.data }}\"\n }\n }\n ]\n }\n ]\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "openRouterApi"
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
},
"openRouterApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "a5d3084d-8652-467b-9848-2257f82c5470",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
-2560,
800
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "fe528286-12a1-4fbc-9065-0785503ca73b",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
-2752,
848
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "c42bc664-49f9-4c83-a2fd-b72a9a5110b2",
"name": "Product_photo",
"type": "string",
"value": "={{ $('User Asset Base').item.json.data }}"
},
{
"id": "d18d3273-1c1f-4da6-8d44-31f0bfefe272",
"name": "Product_description",
"type": "string",
"value": "={{ JSON.parse(($json.choices?.[0]?.message?.content || '').replace(/^```json\\s*|\\s*```$/g, '')).description || '' }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "62f522b6-85de-4ce0-9aad-275a69ef1d32",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4576,
592
],
"parameters": {
"color": 6,
"width": 3456,
"height": 608,
"content": "## 1. Product page + asset preparation\n\n**Double click** to edit me.\n\n### What happens here\n\n- The workflow starts with a simple form:\n - **Product URL**\n - **Logo**\n - **Product photo**\n\n- Uploaded assets are separated and prepared\n- The **logo** is converted for later use in image generation\n- The **product photo** is analyzed to understand what kind of product visual it is\n- The product page is fetched and converted into readable text\n- That text is cleaned into one usable source for analysis\n\n### Why this matters\n\nThis step builds the raw input for the workflow:\n- product page context\n- brand asset\n- product visual asset\n\nWithout this layer, the ad would be much more generic.\n\n### Output\n\n- cleaned product page text\n- processed logo\n- processed product image\n- short description of the uploaded product asset\n"
},
"typeVersion": 1
},
{
"id": "bb89385d-c1e3-4e0d-ba62-28d0f7f91cab",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4576,
112
],
"parameters": {
"width": 656,
"height": 432,
"content": "## Setup before running\n\n### Required credentials\n\n- **Anthropic account** \nUsed for website/product analysis and ad concept creation\n\n- **OpenRouter account** \nUsed for product image analysis and final image generation\n\n- **Google Drive account** \nUsed only if you want the final ad uploaded automatically\n\n### Form inputs required\n\n- **Product URL** \u2014 required\n- **Logo** \u2014 required\n- **Product photo** \u2014 optional, but recommended\n\n### Important checks\n\n- Make sure the uploaded files are **.jpg, .png, or .webp**\n- Check that your OpenRouter model names are valid\n- If you do not want export, disable the **Upload file** node\n"
},
"typeVersion": 1
},
{
"id": "d400ca4c-d85f-49b5-a838-d42939ec5094",
"name": "Form Input",
"type": "n8n-nodes-base.formTrigger",
"position": [
-3792,
736
],
"parameters": {
"options": {},
"formTitle": "Data input",
"formFields": {
"values": [
{
"fieldLabel": "Product URL",
"requiredField": true
},
{
"fieldType": "file",
"fieldLabel": "Logo",
"requiredField": true,
"acceptFileTypes": ".jpg, .png, .webp"
},
{
"fieldType": "file",
"fieldLabel": "Product photo",
"acceptFileTypes": ".jpg, .png, .webp"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1c5e4c7f-616b-4117-bacd-0792879e248c",
"name": "Split Uploaded Files",
"type": "n8n-nodes-base.code",
"position": [
-3568,
736
],
"parameters": {
"jsCode": "const input = $input.first();\n\nconst binaries = input.binary || {};\nconst json = input.json || {};\n\nreturn Object.entries(binaries).map(([key, value]) => ({\n json: {\n ...json,\n binary_field_name: key,\n fileName: value.fileName,\n mimeType: value.mimeType,\n fileExtension: value.fileExtension,\n },\n binary: {\n data: value\n }\n}));"
},
"typeVersion": 2
},
{
"id": "1b05ff8d-0d6d-47f1-9343-565d188db162",
"name": "Fetch Homepage",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2160,
800
],
"parameters": {
"url": "={{ $json.Website }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "a6f8d30b-574f-4999-8228-42162a5a68fa",
"name": "Base inputs",
"type": "n8n-nodes-base.set",
"position": [
-2384,
800
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "ed0f1505-82b6-4393-a0d8-088055137ec9",
"name": "Website",
"type": "string",
"value": "={{ $('Form Input').item.json.Website.startsWith(\"https\") ? $('Form Input').item.json.Website : \"https://\" + $json.Website }}"
},
{
"id": "1e463093-feb7-4cf9-beea-ba677a4a725d",
"name": "Logo",
"type": "string",
"value": "={{ $json.Logo }}"
},
{
"id": "7eaac756-f390-49b7-88bb-37518a1c4512",
"name": "Product_photo",
"type": "string",
"value": "={{ $json.Product_photo }}"
},
{
"id": "8d736738-b70a-41fb-b63c-e644e6e79d8a",
"name": "Photo_descripition",
"type": "string",
"value": "={{ $json.Product_description }}"
}
]
}
},
"typeVersion": 3.3
},
{
"id": "fdf3c9b2-35c2-4618-a172-e2193690dbe0",
"name": "Extract Website Copy",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1984,
800
],
"parameters": {
"text": "=Identify Language of the dommain:\nInput domain:\n\n{{ $('Base inputs').item.json.Website }}\n- Identify the top-level domain (TLD), including multi-part endings like .com.pl or .co.uk.\n\n- If the TLD corresponds to a specific country, output that country\u2019s dominant language.\n\n- If the TLD is generic or not tied to a country (e.g., .com, .co, .io, .ai, .net, .org, .app, .dev, .tech), DEFAULT to English.\n\n- If unsure or ambiguous, DEFAULT to English. \n\nReturn only the language as a plain string.\nExample: \"English\"\nNo JSON. No arrays. No extra text.",
"options": {},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2,
"alwaysOutputData": true
},
{
"id": "df1bbe2e-9569-4535-878b-6edab1174897",
"name": "Clean text",
"type": "n8n-nodes-base.code",
"position": [
-1328,
992
],
"parameters": {
"jsCode": "// 1) Get array of text blocks from the Aggregate node\nlet arr = $json.data || [];\n\n// 2) Join all text pieces into one long text string\nlet txt = arr.join(\" \");\n\n// 3) Remove markdown headings\ntxt = txt.replace(/^#{1,6}\\s*/gm, \"\");\n\n// 4) Remove tabs and newlines\ntxt = txt.replace(/[\\t\\r]+/g, \" \");\ntxt = txt.replace(/\\n+/g, \" \");\n\n// 5) Remove leftover markdown bullets, dashes, stars\ntxt = txt.replace(/[*\u2022\\-+]{1,2}\\s*/g, \"\");\n\n// 6) Remove multiple spaces\ntxt = txt.replace(/\\s{2,}/g, \" \").trim();\n\n// 7) JSON-escape without wrapping in quotes\nlet jsonSafe = JSON.stringify(txt).slice(1, -1);\n\nreturn {\n json_safe: jsonSafe\n};\n"
},
"typeVersion": 2
},
{
"id": "f622ad68-b16b-437d-ba17-767bdb675548",
"name": "Build Brand Insights",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-3792,
1424
],
"parameters": {
"text": "=You are an ecommerce product analyst.\n\nYour task is to extract structured information strictly from the provided ecommerce website or product page text.\n\nYou must maximize the amount of useful information extracted, but:\n\nDo not invent facts.\nDo not guess or rely on prior knowledge.\nOnly return elements that are directly supported by explicit text or strongly implied within the same paragraph or section.\nIf any element cannot be found, return \"Unknown\" or [].\n\nUse short, clear phrasing.\nNever include marketing fluff \u2014 only what the text clearly states.\n\nWEBSITE / PRODUCT PAGE TEXT\n{{ $json.json_safe }}\n\nTASKS\n\nProduct / Brand Name\nExtract the product name if clearly visible in the text. Prefer product titles, headings, hero sections, product descriptions, or structured product information. Remove domain suffixes (.com, .io, etc.). If both brand and product name appear, include the most relevant product name first and brand second if useful. If only brand is visible, return the brand name. If unsure \u2192 \"Unknown\". Use the website URL only as a weak signal when the name is otherwise unclear.\n\nProduct Summary\n1\u20132 neutral, factual sentences describing what the product is and what it does, based ONLY on the text.\n\nProduct Category\nShort classification of the product type, max 4 words.\nExamples: skincare product, fitness equipment, kitchen accessory, pet product, apparel, supplement, home decor.\nIf unclear \u2192 \"Unknown\".\n\nCustomer Group\nWho the product is for. Extract exactly as worded when possible. If multiple groups appear, list them separated by commas. If unclear \u2192 \"Unknown\".\n\nUse Cases\nList the main situations, needs, or occasions where the product is used.\n\nProblems / Needs\nList the core customer pain points, needs, or desires described or clearly implied.\n\nSolution\nShort, factual explanation of how the product addresses the problems or needs.\n\nKey Product Features\nExtract main functional or physical attributes.\nExamples: material, ingredients, size, color, design, compatibility, included items, mechanism, construction, formulation, care instructions.\nDo not turn benefits into features.\n\nKey Benefits / Differentiators\nExtract value outcomes explicitly stated.\nExamples: saves time, improves comfort, reduces mess, supports hydration, easier storage, better fit, longer-lasting, travel-friendly.\n\nProof / Trust Signals\nExtract explicit trust elements if present.\nExamples: reviews, ratings, guarantees, certifications, awards, clinical tests, warranty, free returns, shipping claims, before/after claims, customer testimonials.\nIf none \u2192 [].\n\nOffer / Pricing\nExtract price, discount, bundle, subscription, free shipping, trial, payment plan, or urgency claims if clearly stated.\nIf none \u2192 \"Unknown\".\n\nBrand Voice & Tone\nDescribe the tone based only on the text.\nExamples: premium, playful, clinical, minimalist, friendly, bold, luxury, practical, eco-conscious.\nIf unclear \u2192 \"Unknown\".\n\nBusiness Type\nShort classification of the business type, max 3 words.\nUse: Ecommerce.\n\n---\n\nAfter extracting all fields, write a ~250-word ecommerce marketing brief synthesizing ONLY the extracted information.\n\nRules for the brief:\n- ~250 words.\n- No fluff.\n- Very dense and insight-heavy.\n- Explain the customer\u2019s world, their frustrations, desires, and purchase motivations.\n- Show how the product fits the need \u2192 solution \u2192 benefit \u2192 purchase reason arc.\n- Mention concrete features, benefits, proof, and offer details only when extracted.\n- Maintain the extracted tone.\n- No made-up facts.\n\n---\n\nOUTPUT FORMAT (Valid JSON Only)\n\n{\n \"product_name\": \"\",\n \"product_summary\": \"\",\n \"product_category\": \"\",\n \"customer_group\": \"\",\n \"use_cases\": [],\n \"problems_needs\": [],\n \"solution\": \"\",\n \"key_product_features\": [],\n \"key_benefits\": [],\n \"proof_trust_signals\": [],\n \"offer_pricing\": \"\",\n \"brand_voice\": \"\",\n \"marketing_brief\": \"\",\n \"business_type\": \"Ecommerce\"\n}\n\nReturn ONLY this JSON object. No explanations, no markdown, no extra text.",
"options": {
"passthroughBinaryImages": true
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2,
"alwaysOutputData": true
},
{
"id": "a9c75654-7250-49f0-8e0b-21348915206e",
"name": "Create Ad Concept",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-3440,
1424
],
"parameters": {
"text": "=You are a senior ecommerce marketing strategist, creative director, and conceptual advertising designer known for bold, memorable, conversion-focused product campaigns.\n\nYour task is to create one complete ecommerce advertisement concept that communicates clear product value through strong product presentation, buyer motivation, and playful or unexpected creative expression when appropriate.\n\nAll reasoning must rely strictly on the provided inputs.\nDo not introduce external assumptions, examples, statistics, claims, use cases, or predefined metaphors.\n\n--------------------------------\nLANGUAGE\n\nCreate all ad text in:\n{{ $json.output.language || \"English\" }}\n\n--------------------------------\nPRIMARY CONTEXT\n\nProduct / Brand Name:\n{{ $json.output.product_name }}\n\nProduct Summary:\n{{ $json.output.product_summary }}\n\nProduct Category:\n{{ $json.output.product_category }}\n\nCustomer Group:\n{{ $json.output.customer_group }}\n\nUse Cases:\n{{ $json.output.use_cases }}\n\nProblems / Needs:\n{{ $json.output.problems_needs }}\n\nKey Benefits:\n{{ $json.output.key_benefits }}\n\nKey Product Features:\n{{ $json.output.key_product_features }}\n\nProof / Trust Signals:\n{{ $json.output.proof_trust_signals }}\n\nOffer / Pricing:\n{{ $json.output.offer_pricing }}\n\nBrand Voice:\n{{ $json.output.brand_voice }}\n\nMarketing Brief:\n{{ $json.output.marketing_brief }}\n\n--------------------------------\nPRODUCT ASSET / PRODUCT DESCRIPTION\n\n{{ $('Merge').item.json.Product_description }}\n\n--------------------------------\nASSET INTERPRETATION\n\nFirst, analyze the provided product asset or product description.\n\nDetermine:\n- what type of product visual it represents: physical product, packaging, lifestyle image, product detail, ingredient/material close-up, bundle, before/after, icon, abstract graphic, or other\n- what concrete product feature, use case, benefit, or buyer desire it can support\n- how the product should influence the ad composition\n\nThe product must be visually central.\nDo not make the product decorative or secondary.\n\nIf the asset shows a physical ecommerce product:\n- keep the product recognizable and desirable\n- do not distort, obscure, crop heavily, or redesign the product\n- the ad concept must be built around making the product feel valuable, useful, and easy to understand\n\n--------------------------------\nCORE CREATIVE REQUIREMENT\n\nThe advertisement must:\n- communicate why someone should want or buy the product\n- make the product benefit clear quickly\n- connect the product to a real need, desire, use case, or outcome from the inputs\n- remain believable and grounded in the provided text\n- use playful, unexpected, or bold creative expression only when it strengthens the buying reason\n\nEcommerce ads do not always need a classic headline + subheadline structure.\nChoose the copy structure that best fits the product, offer, and creative idea.\n\nAllowed ad copy structures:\n- headline + short support line + CTA\n- punchy product claim + CTA\n- benefit-led headline + feature chips\n- problem line + solution line + CTA\n- offer-led headline + product benefit + CTA\n- testimonial-style line + CTA, only if testimonials are provided\n- comparison-style line, only if comparison is clearly supported by inputs\n- simple product label + benefit badges + CTA\n\nDo not force a subheadline if a shorter ecommerce layout would be stronger.\n\n--------------------------------\nPART 1 \u2014 COPY CREATION\n\nCreate exactly one ecommerce copy concept.\n\nThe concept must include:\n\n1. copy_structure\nChoose one:\n- \"headline_support_cta\"\n- \"claim_cta\"\n- \"benefit_chips_cta\"\n- \"problem_solution_cta\"\n- \"offer_benefit_cta\"\n- \"product_label_badges_cta\"\n- \"testimonial_cta\"\n\n2. primary_text\nThe main visible text of the ad.\nMaximum 7 words.\nMust be clear, specific, and product-relevant.\n\n3. secondary_text\nOptional supporting text.\nMaximum 12 words.\nUse only if it improves clarity.\nIf not needed, return \"\".\n\n4. microcopy_elements\nReturn 0\u20133 short elements such as feature chips, benefit badges, offer labels, or product-use labels.\nEach element maximum 4 words.\nOnly include elements supported by the inputs.\n\n5. cta_text\nMaximum 3 words.\nShort, natural, action-oriented, and ecommerce-appropriate.\n\nCOPY RULES:\n- use concrete product value, not generic brand language\n- make the buying reason clear\n- keep the copy visually scannable\n- avoid long explanatory sentences\n- avoid unsupported numbers, guarantees, reviews, discounts, or claims\n- avoid vague phrases like: unlock, empower, seamless, game-changing, life-changing, premium quality, must-have\n- do not mention the customer group unless the website text does\n- no unusual spelling\n- plural \u201cs\u201d must be lowercase\n\n--------------------------------\nPART 2 \u2014 VISUAL STRUCTURE\n\nCREATIVE IDEA\n\nDescribe:\n- the product-led creative angle\n- the buyer need, desire, or use case it highlights\n- any playful or unexpected twist, if useful\n- why the idea remains credible for ecommerce\n\nMAIN VISUAL\n\nDescribe:\n- how the product appears as the central focal point\n- the scene, setting, object arrangement, or product display\n- how benefits, features, use cases, or offer details appear visually\n- how to keep the product recognizable and desirable\n\nLAYOUT\n\nDefine:\n- the relationship between product, primary text, optional secondary text, microcopy elements, and CTA\n- whitespace, balance, and first-glance clarity\n- whether the layout should feel product-shot, lifestyle, editorial, comparison, offer-led, or badge-led\n\nSTYLE DIRECTION\n\nSpecify:\n- modern ecommerce ad aesthetic\n- clean product-focused composition\n- controlled color usage\n- polished lighting, depth, or flat graphic precision\n- paid-media-ready finish\n- tone aligned with the extracted brand voice\n\n--------------------------------\nOUTPUT FORMAT\n\nReturn only valid JSON:\n\n{\n \"copy_structure\": \"\",\n \"primary_text\": \"\",\n \"secondary_text\": \"\",\n \"microcopy_elements\": [],\n \"cta_text\": \"\",\n \"creative_idea\": \"\",\n \"main_visual\": \"\",\n \"layout_description\": \"\",\n \"style_direction\": \"\"\n}\n\nReturn only the JSON object. No markdown, no explanations, no extra text.",
"options": {},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 2.2
},
{
"id": "9a1544fc-5881-4026-9902-72cb7a9f20be",
"name": "Generate Ad Image",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"maxTries": 5,
"position": [
-3088,
1424
],
"parameters": {
"url": "https://openrouter.ai/api/v1/chat/completions",
"method": "POST",
"options": {
"response": {
"response": {
"neverError": true
}
}
},
"jsonBody": "={\n \"model\": \"google/gemini-3-pro-image-preview\",\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": \"Create a premium ecommerce product advertisement based strictly on the structured concept, logo, and product photo below.\\n\\nIMAGE INPUTS:\\n- Image 1 is the brand logo. Use it as a small brand mark only.\\n- Image 2 is the product photo. This is the main product asset.\\n\\nAD CONCEPT SOURCE:\\nCopy structure: {{ $json.output.copy_structure }}\\nCreative idea: {{ $json.output.creative_idea }}\\nMain visual: {{ $json.output.main_visual }}\\nLayout: {{ $json.output.layout_description }}\\nStyle direction: {{ $json.output.style_direction }}\\n\\nDISPLAYED TEXT CONTENT:\\nUse these exact words. Do not print labels like \\\"primary text\\\", \\\"secondary text\\\", \\\"CTA\\\", or \\\"microcopy\\\".\\nPrimary text: {{ $json.output.primary_text }}\\nSecondary text: {{ $json.output.secondary_text }}\\nMicrocopy elements: {{ $json.output.microcopy_elements }}\\nCall-to-action text: {{ $json.output.cta_text }}\\n\\nECOMMERCE AD COMPOSITION:\\n- Design the ad around the product photo as the main visual focal point.\\n- The product must be clearly visible, recognizable, desirable, and visually central.\\n- Do not redesign, distort, replace, or obscure the product.\\n- Do not turn the product into a different object.\\n- The product photo should feel intentionally integrated into a premium ecommerce layout.\\n- The ad should communicate one clear buying reason in one glance.\\n\\nCOPY LAYOUT RULES:\\n- Use the primary text as the main attention hook.\\n- The primary text must be dominant, readable, and visually clean.\\n- Use secondary text only if it is not empty.\\n- If secondary text is empty, do not invent supporting copy.\\n- Microcopy elements may appear as small chips, badges, labels, or benefit tags.\\n- Use only the provided microcopy elements. Do not invent extra badges or claims.\\n- CTA must be a distinct button or label.\\n- Never hide, crop, distort, omit, rewrite, or add to the provided text.\\n- Keep all text legible, crisp, and suitable for paid social.\\n\\nLOGO USAGE:\\n- Use the logo subtly, usually near the top or corner.\\n- The logo must not compete with the product or primary text.\\n- Do not recolor or distort the logo unless needed for readability.\\n\\nPRODUCT VISUAL RULES:\\n- Make the product look premium, clean, and conversion-ready.\\n- Use lighting, framing, shadow, surface, or background treatment to make the product desirable.\\n- If the concept suggests a lifestyle, editorial, comparison, offer-led, or badge-led layout, apply it without changing the actual product.\\n- Do not add unrelated props, random icons, mascots, people, surreal objects, or decorative clutter.\\n- Any supporting visual elements must directly reinforce the product benefit, use case, feature, or offer from the concept.\\n\\nECOMMERCE STYLE RULES:\\n- Create a polished paid-media ecommerce ad.\\n- Use a bright, clean, uncluttered background.\\n- Use strong product hierarchy and generous whitespace.\\n- Use controlled contrast and crisp typography.\\n- Use restrained shadows and premium product-marketing lighting.\\n- Use brand colors only as controlled accents, CTA treatment, badges, or small layout details.\\n- Avoid glossy 3D, plastic-looking materials, neon glow, sci-fi styling, excessive reflections, overdone gradients, visual noise, and generic stock-ad styling.\\n\\nFINAL RENDER GOAL:\\nThe final ad should feel like a premium ecommerce static ad: product-led, easy to understand instantly, visually desirable, conversion-focused, clean, modern, and credible.\"\n },\n {\n \"type\": \"image_url\",\n \"image_url\": {\n \"url\": \"data:{{ $('Form Input').item.json.Logo[0].mimetype }};base64,{{ $('Merge').item.json.Logo }}\"\n }\n },\n {\n \"type\": \"image_url\",\n \"image_url\": {\n \"url\": \"data:{{ $('Form Input').item.json['Product photo'][0].mimetype }};base64,{{ $('Merge').item.json.Product_photo }}\"\n }\n }\n ]\n }\n ],\n \"modalities\": [\n \"image\",\n \"text\"\n ],\n \"stream\": false\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "openRouterApi"
},
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "0a970887-e3d9-407d-9ba3-756f2cca6823",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4592,
1248
],
"parameters": {
"color": 5,
"width": 3472,
"height": 624,
"content": "## 2. Product insights + ad generation\n\n**Double click** to edit me.\n\n### What happens here\n\n- Claude analyzes the product page text and extracts structured ecommerce insights such as:\n\n- Then it creates one ad concept with:\n - primary text\n - optional secondary text\n - microcopy / badges\n - CTA\n - creative idea\n - main visual direction\n - layout direction\n - style direction\n\n- Finally, the image model generates the ad and can export it as a file\n\n### Why this matters\n\nThis is where raw product-page information becomes:\n1. **product understanding**\n2. **creative direction**\n3. **final ecommerce ad output**\n\n### Output\n\n- structured product insights\n- ecommerce ad concept\n- generated static ad\n- optional exported file"
},
"typeVersion": 1
},
{
"id": "bac5199d-295d-4f9d-ae28-13f43fa4f389",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4576,
-128
],
"parameters": {
"color": 4,
"width": 656,
"height": 208,
"content": "## What this workflow does\n\nThis workflow turns a **product URL, logo, and product image** into a ready ecommerce ad creative.\n\nIt reads the product page, extracts the product context, analyzes the uploaded image, builds a product-focused ad concept with Claude, and then generates the final static ad with NanoBanana through OpenRouter.\n\nThis is useful when you want more structured, product-aware ecommerce ads instead of generic AI outputs."
},
"typeVersion": 1
},
{
"id": "e65c8db3-e0b9-48bd-998e-145bb636aa9e",
"name": "Anthropic Chat Model2",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
-2000,
960
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-5-20250929",
"cachedResultName": "Claude Sonnet 4.5"
},
"options": {}
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "0f5bd2aa-e524-4fe1-875f-a25533e10345",
"connections": {
"If": {
"main": [
[
{
"node": "User Asset Base64",
"type": "main",
"index": 0
}
],
[
{
"node": "User Asset Base",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Base inputs",
"type": "main",
"index": 0
}
]
]
},
"Aggregate1": {
"main": [
[
{
"node": "Clean text",
"type": "main",
"index": 0
}
]
]
},
"Clean text": {
"main": [
[
{
"node": "Build Brand Insights",
"type": "main",
"index": 0
}
]
]
},
"Form Input": {
"main": [
[
{
"node": "Split Uploaded Files",
"type": "main",
"index": 0
}
]
]
},
"Base inputs": {
"main": [
[
{
"node": "Fetch Homepage",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Text extract": {
"main": [
[
{
"node": "Aggregate1",
"type": "main",
"index": 0
}
]
]
},
"Fetch Homepage": {
"main": [
[
{
"node": "Extract Website Copy",
"type": "main",
"index": 0
}
]
]
},
"set outputfile": {
"main": [
[
{
"node": "Convert to File2",
"type": "main",
"index": 0
}
]
]
},
"User Asset Base": {
"main": [
[
{
"node": "Call Claude - Photo Evaluation",
"type": "main",
"index": 0
}
]
]
},
"Convert to File2": {
"main": [
[
{
"node": "Upload file",
"type": "main",
"index": 0
}
]
]
},
"Create Ad Concept": {
"main": [
[
{
"node": "Generate Ad Image",
"type": "main",
"index": 0
}
]
]
},
"Generate Ad Image": {
"main": [
[
{
"node": "set outputfile",
"type": "main",
"index": 0
}
]
]
},
"User Asset Base64": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Build Brand Insights": {
"main": [
[
{
"node": "Create Ad Concept",
"type": "main",
"index": 0
}
]
]
},
"Extract Website Copy": {
"main": [
[
{
"node": "Text extract",
"type": "main",
"index": 0
}
]
]
},
"Split Uploaded Files": {
"main": [
[
{
"node": "If",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model1": {
"ai_languageModel": [
[
{
"node": "Create Ad Concept",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Anthropic Chat Model2": {
"ai_languageModel": [
[
{
"node": "Extract Website Copy",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Anthropic Chat Model3": {
"ai_languageModel": [
[
{
"node": "Build Brand Insights",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser2": {
"ai_outputParser": [
[
{
"node": "Create Ad Concept",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Structured Output Parser3": {
"ai_outputParser": [
[
{
"node": "Build Brand Insights",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Call Claude - Photo Evaluation": {
"main": [
[
{
"node": "Edit Fields",
"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.
anthropicApigoogleDriveOAuth2ApiopenRouterApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow is designed for ecommerce brands, marketers, agencies, and content teams who want to generate static product ads faster from minimal product input.
Source: https://n8n.io/workflows/15405/ — 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.
This workflow is designed for marketers, founders, agencies, and content teams who want to generate static ad creatives faster from minimal brand input.
Creators, agencies, and marketers who need short-form vertical video at scale. Anyone who wants to turn a topic into an edited “talking shorts” style clip without opening a video editor.
This automated workflow transforms simple text descriptions into professional 8-second videos using Google's cutting-edge VEO3 AI model. Users submit video ideas through a web form, and the system aut
🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.
This workflow is designed for marketers, founders, agencies, and product teams who want to understand how real customers talk about a product category, market, or problem space.