This workflow corresponds to n8n.io template #15236 — 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": "8z4vIOSX9A19vll0",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Generate AI Ads from Website and Images with Claude + NanoBanana",
"tags": [],
"nodes": [
{
"id": "bbe1822b-2fb8-4b43-8a8d-e27c32052b1c",
"name": "Text extract",
"type": "n8n-nodes-base.markdown",
"position": [
1664,
1632
],
"parameters": {
"html": "={{ $('Fetch Homepage').item.json.data }}",
"options": {
"ignore": "a,img"
}
},
"typeVersion": 1
},
{
"id": "8534c6eb-24b6-4368-a74c-e1a8c2cbe964",
"name": "HTML",
"type": "n8n-nodes-base.html",
"onError": "continueRegularOutput",
"position": [
1088,
1872
],
"parameters": {
"options": {},
"operation": "extractHtmlContent",
"extractionValues": {
"values": [
{
"key": "navLinks",
"attribute": "href",
"cssSelector": "nav a, header nav a, .menu a, .navbar a, .main-menu a, #menu a",
"returnArray": true,
"returnValue": "attribute"
}
]
}
},
"typeVersion": 1.2,
"alwaysOutputData": true
},
{
"id": "9ad6bfda-bbd9-4648-99f9-d8ed74018f71",
"name": "Get website (text)",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
2080,
1872
],
"parameters": {
"url": "={{ $json.URLs }}",
"options": {}
},
"typeVersion": 4.2,
"alwaysOutputData": true
},
{
"id": "f3f7f397-05ca-4bdd-a9bc-23b7b43b1dd3",
"name": "Text extract1",
"type": "n8n-nodes-base.markdown",
"onError": "continueRegularOutput",
"position": [
2256,
1872
],
"parameters": {
"html": "={{ $json.data }}",
"options": {
"ignore": "a,img"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "5e24417e-5589-4e55-b958-81c021646e36",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"position": [
2592,
1744
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "055019dc-d541-4999-ad6b-613d3e5aacd5",
"name": "Aggregate1",
"type": "n8n-nodes-base.aggregate",
"position": [
2816,
1744
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "data"
}
]
}
},
"typeVersion": 1
},
{
"id": "b29b4e21-7a98-48b8-bdc2-37df54b2ee39",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
1440,
2032
],
"parameters": {
"jsonSchemaExample": "[\n \"/first-handle/\",\n \"/second-handle/\",\n \"/third-handle/\",\n \"/fourth-handle/\"\n]"
},
"typeVersion": 1.3
},
{
"id": "0d9e9372-c148-4fad-b9f1-e93561da749b",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
1664,
1872
],
"parameters": {
"options": {},
"fieldToSplitOut": "output"
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "73d38d83-a3a1-4ab7-af1b-15a3badbc78f",
"name": "Aggregate2",
"type": "n8n-nodes-base.aggregate",
"position": [
2432,
1872
],
"parameters": {
"options": {},
"fieldsToAggregate": {
"fieldToAggregate": [
{
"fieldToAggregate": "data"
}
]
}
},
"typeVersion": 1
},
{
"id": "2680fcb1-8c1e-4840-b696-186a56d6c15b",
"name": "Upload file",
"type": "n8n-nodes-base.googleDrive",
"position": [
2016,
2368
],
"parameters": {
"name": "generated-ad.png",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": ""
}
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "f6f49fd8-b06f-455f-9bd1-75d83b9f9f0d",
"name": "Structured Output Parser2",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
1136,
2608
],
"parameters": {
"jsonSchemaExample": "{\n \"headline1\": \"\",\n \"headline2\": \"\",\n \"subheadline1\": \"\",\n \"subheadline2\": \"\",\n \"cta_text1\": \"\",\n \"cta_text2\": \"\",\n \"main_visual1\": \"\",\n \"layout_description1\": \"\",\n \"style_direction1\": \"\"\n}"
},
"typeVersion": 1.3
},
{
"id": "58d7387d-d8bc-4178-a2db-0132cba1410d",
"name": "Anthropic Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
1008,
2608
],
"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": "11c3947f-7fd3-4548-928f-4738c8643b09",
"name": "Convert to File2",
"type": "n8n-nodes-base.convertToFile",
"onError": "continueErrorOutput",
"position": [
1792,
2384
],
"parameters": {
"options": {},
"operation": "toBinary",
"sourceProperty": "outputfile"
},
"typeVersion": 1.1
},
{
"id": "edd48827-60d7-4758-be1c-3030b13dba87",
"name": "set outputfile",
"type": "n8n-nodes-base.set",
"position": [
1568,
2384
],
"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": "69f180fc-03bc-4b49-9b00-1b2862abb022",
"name": "Anthropic Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
1312,
2032
],
"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": "4083706d-ae3d-4741-a782-3d98011506ce",
"name": "Anthropic Chat Model3",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
656,
2608
],
"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": "01033617-2c19-4b2a-b9dc-7a5a93e97836",
"name": "Structured Output Parser3",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
784,
2608
],
"parameters": {
"jsonSchemaExample": "{\n \"product_name\": \"\",\n \"product_summary\": \"\",\n \"customer_group\": \"\",\n \"problems\": [],\n \"solution\": \"\",\n \"key_features\": [],\n \"key_benefits\": [],\n \"brand_voice\": \"\",\n \"marketing_brief\": \"\",\n \"business_type\":\"\"\n}"
},
"typeVersion": 1.3
},
{
"id": "9971ef88-8d4e-4ad5-ac64-04c0f5d9df34",
"name": "User Asset Base64",
"type": "n8n-nodes-base.extractFromFile",
"position": [
1520,
1168
],
"parameters": {
"options": {},
"operation": "binaryToPropery",
"destinationKey": "Logo",
"binaryPropertyName": "=data"
},
"typeVersion": 1
},
{
"id": "a26f4f8d-cb8f-4660-a763-c34b4cf2f293",
"name": "If",
"type": "n8n-nodes-base.if",
"position": [
1072,
1184
],
"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": "947aaac1-97d9-4610-a324-d52d093a0f62",
"name": "User Asset Base",
"type": "n8n-nodes-base.extractFromFile",
"position": [
1296,
1312
],
"parameters": {
"options": {},
"operation": "binaryToPropery",
"binaryPropertyName": "=data"
},
"typeVersion": 1
},
{
"id": "ff7f3b83-e87b-4c4e-8f20-c117a6ae8cc2",
"name": "Call Claude - Photo Evaluation",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"maxTries": 2,
"position": [
1520,
1312
],
"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"
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "06f774b1-afab-41bb-a3db-3f4c6ab4dd34",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
2080,
1392
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "370ad4bd-92b7-4cb1-93b8-dace4f60e10b",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
1744,
1296
],
"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": "a9f457ac-2e48-4f33-aeba-b6039a2b8b31",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-16,
1008
],
"parameters": {
"color": 6,
"width": 3232,
"height": 528,
"content": "## 1. Form Input + asset preparation\n\n**Double click** to edit me.\n\n### What happens here\n\n- The workflow starts with a simple form:\n - **Website**\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 visual it is\n\n### Why this matters\n\nThis step prepares the core inputs for the workflow:\n- the **brand identity**\n- the **main visual asset**\n- the **website source**\n\n### Output\n\n- normalized website URL\n- processed logo\n- processed product image\n- short visual description of the uploaded asset"
},
"typeVersion": 1
},
{
"id": "3db85995-6e01-4a07-ac93-73cd4974ce20",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
176
],
"parameters": {
"width": 656,
"height": 768,
"content": "## Setup before running\n\n**Double click** to edit me.\n\n### Required credentials\n\n- **Anthropic account** \nUsed by:\n - **Extract Sub-Website Copy**\n - **Extract Website Copy**\n - **Build Brand Insights**\n - **Create Ad Concept**\n\n- **OpenRouter account** \nUsed by:\n - **Call Claude - Photo Evaluation**\n - **Generate Ad Image**\n\n- **Google Drive account** \nUsed by:\n - **Upload file**\n\n### What to connect\n\n1. In all **Anthropic Chat Model** nodes, connect your **Anthropic API credential**\n2. In **Call Claude - Photo Evaluation** and **Generate Ad Image**, connect your **OpenRouter credential**\n3. In **Upload file**, connect your **Google Drive OAuth credential**\n\n### Form inputs required\n\n- **Website** \u2014 required\n- **Logo** \u2014 required\n- **Product photo** \u2014 optional\n\n### Important checks\n\n- Accepted files should be **.jpg, .png, .webp**\n- Make sure the OpenRouter model names are valid in your account\n- If you do not want export to Drive, disable **Upload file**"
},
"typeVersion": 1
},
{
"id": "e2d66c93-1c98-4d47-b923-27db1011b1e2",
"name": "Form Input",
"type": "n8n-nodes-base.formTrigger",
"position": [
624,
1184
],
"parameters": {
"options": {},
"formTitle": "Data input",
"formFields": {
"values": [
{
"fieldLabel": "Website",
"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": "cf42ab34-b0da-45b6-974e-810109e0d77f",
"name": "Split Uploaded Files",
"type": "n8n-nodes-base.code",
"position": [
848,
1184
],
"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": "4b053e36-dc8f-4602-bd4a-d1ecb707c0c1",
"name": "Fetch Homepage",
"type": "n8n-nodes-base.httpRequest",
"position": [
864,
1728
],
"parameters": {
"url": "={{ $json.Website }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "23540f2e-1940-422b-bf3d-5d6107328d45",
"name": "Base inputs",
"type": "n8n-nodes-base.set",
"position": [
640,
1728
],
"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": "737ac75f-e4b8-464d-b23b-934b7c7e62f6",
"name": "Extract Website Copy",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1312,
1632
],
"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": "4c69ac30-1e19-487c-b695-163c493d01e0",
"name": "Extract Sub-Website Copy",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1312,
1872
],
"parameters": {
"text": "=From the list of website handles, select up to 4 handles that will likely contain the most valuable marketing insights, brand tone, and product messaging.\nExclude the main homepage.\n\nList:\n{{ $json.navLinks }}\nPRIORITIZE HANDLES LIKE:\n/product/, /features/, /solutions/, /platform/, /pricing/, /customers/, /use-cases/, /blog/, /resources/, /why-us/, /about/\n\nIGNORE:\ncareers, legal, login, language variants (/de/, /fr/), support pages.\n\nOUTPUT FORMAT (strict):\n\n[\n \"/first-handle/\",\n \"/second-handle/\",\n \"/third-handle/\",\n \"/fourth-handle/\"\n]",
"options": {},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2,
"alwaysOutputData": true
},
{
"id": "d89afb84-1a5b-40f1-888b-c060b3ae29f1",
"name": "Map websites",
"type": "n8n-nodes-base.set",
"onError": "continueRegularOutput",
"position": [
1888,
1872
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "d82fe5ee-9427-493d-8a0e-5e96ae17bf4c",
"name": "URLs",
"type": "string",
"value": "={{ $json.output }}"
}
]
}
},
"typeVersion": 3.4,
"alwaysOutputData": true
},
{
"id": "2adb66ab-6ea8-434a-baf7-6e117e3306fa",
"name": "Clean text",
"type": "n8n-nodes-base.code",
"position": [
3008,
2016
],
"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": "478a0621-d538-4bb5-b69b-8f1185ebbbe0",
"name": "Build Brand Insights",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
640,
2384
],
"parameters": {
"text": "=You are a B2B SaaS brand analyst.\n\nYour task is to extract structured information strictly from the provided website text.\n\nYou must maximize the amount of 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 TEXT\n{{ $json.json_safe }}\n\nTASKS\n\nProduct / Brand Name \nExtract only if clearly visible in the text. Prefer headings, titles, product descriptions, hero sections, or navigation labels. Remove domain suffixes (.com, .io, etc.). Capitalize first letter. If multiple appear, pick the most prominent. If unsure \u2192 \"Unknown\". Look at the website url to determine. And how many times it is used.\n\nProduct Summary \n1\u20132 neutral, factual sentences describing what the product does, based ONLY on the text.\n\nCustomer Group \nWho the product is for (ICP). Extract exactly as worded. If multiple groups appear, just write them afer,.\n\nProblems \nList the core pain points described or clearly implied.\n\nSolution \nShort, factual explanation of how the product solves the problems.\n\nKey Features \nExtract main functional capabilities. Do not turn benefits into features.\n\nKey Benefits / Differentiators \nExtract value outcomes explicitly stated.\n\nBrand Voice & Tone \nDescribe the tone (e.g., friendly, technical, formal). If unclear \u2192 \"Unknown\".\n\nBusiness type\nShort classification (max 3 words) of the business type helping to identify the positioning like (B2B SaaS, Ecommerce, Services etc.)\n\n\n---\n\nAfter extracting all fields, write a **~250-word marketing brief** synthesizing ONLY the extracted information. \nRules for the brief:\n- ~250 words.\n- No fluff.\n- Very dense and insight-heavy (\u201craw meat\u201d).\n- Explain the ICP\u2019s world, their frustrations, and motivations.\n- Show how the product fits the problem \u2192 solution \u2192 outcome arc.\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 \"customer_group\": \"\",\n \"problems\": [],\n \"solution\": \"\",\n \"key_features\": [],\n \"key_benefits\": [],\n \"brand_voice\": \"\",\n \"marketing_brief\": \"\",\n\"business_type\":\"\"\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": "e0c51b88-413e-4930-b523-a080f69db1a0",
"name": "Create Ad Concept",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
992,
2384
],
"parameters": {
"text": "=You are a senior {{ $json.output.business_type }} marketing strategist, creative director, and conceptual advertising designer known for bold, intelligent, and memorable campaigns.\n\nYour task is to create a complete value-proposition advertisement concept that combines clear product value with playful, unexpected creative expression while remaining credible for a professional {{ $json.output.business_type }} audience.\n\nAll reasoning must rely strictly on the provided inputs.\nDo not introduce external assumptions, examples, or predefined metaphors.\n\n--------------------------------\nLANGUAGE\n\nCreate all text in:\n\n\n--------------------------------\nPRIMARY CONTEXT (USE ONLY THIS)\n\nBrand Name:\n{{ $json.output.product_name }}\n\nBrand Summary:\n{{ $json.output.product_summary }}\n\nCustomer Group:\n{{ $json.output.customer_group }}\nKey Benefits:\n{{ $json.output.key_benefits }}\nKey Features:\n{{ $json.output.key_features }}\n\nDesired Outcomes:\n{{ $json.output.key_benefits }}\n\nMARKETING BRIEF\n{{ $json.output.marketing_brief }}\n\n\n--------------------------------\nASSET INTERPRETATION (MANDATORY)\n\n{{ $('Merge').item.json.Product_description }}\n\nDetermine:\n- what type of visual it is (character, UI/dashboard, object, icon, abstract graphic, or other)\n- what real product meaning or function it represents\n- how it should structurally influence the advertisement composition\n\nThe final visual concept must always be built around this asset.\nThe asset must never be decorative or optional.\n\nUI-SPECIFIC RULE:\nIf the asset is a UI/dashboard:\n- the UI must be clearly visible, readable, and undistorted\n- it must occupy the primary focal area of the advertisement\n- the layout must be designed to showcase the UI as the main proof of value\n- no heavy perspective, blur, cropping, or decorative obstruction is allowed\n- supporting visuals may exist only to reinforce the UI, never compete with it\n\n--------------------------------\nCORE CREATIVE REQUIREMENT\n\nThe advertisement must:\n\u2192 communicate real product value clearly and instantly\n\u2192 use an unexpected, bold, or playful visual idea\n\u2192 remain intelligent, professional, and credible for {{ $json.output.business_type }}\n\nPlayfulness must serve clarity, not replace it.\n\n--------------------------------\nPART 1 \u2014 COPY CREATION\n\nHEADLINES\n\nGenerate exactly 2 headlines.\nMaximum 6 words each.\n\nRequirements:\n- clear connection to real product value\n- confident, bold, or witty tone\n- still understandable for professional audience\n- do not mention the customer group\n- one headline must be phrased as a question\n- no unusual spelling\n\nSUBHEADLINES\n\nGenerate exactly 2 subheadlines.\nMaximum 14 words each.\n\nRequirements:\n- explain how the product delivers the value\n- grounded in real features or benefits\n- concrete and believable\n- support the bold tone without exaggeration\n\nCTA TEXT\n\nGenerate exactly 2 CTAs.\nMaximum 3 words each.\n\nRequirements:\n- short, confident, action-oriented\n- natural for {{ $json.output.business_type }} interaction\n- no unusual spelling\n- plural \u201cs\u201d must be lowercase\n\n--------------------------------\nPART 2 \u2014 VISUAL STRUCTURE\n\nCREATIVE CONTRAST LOGIC\n\nDefine:\n- the unexpected or playful visual twist\n- how the twist reveals real product value\n- why the idea remains credible for {{ $json.output.business_type }}\n\n\nMAIN VISUAL\n\nDescribe:\n- a bold, memorable central scene or object\n- strong focal hierarchy and visual clarity\n- balance between fun and professional tone\n\nLAYOUT\n\nDefine:\n- clear relationship between visual idea, headline, and CTA\n- readable composition with confident whitespace\n\nSTYLE DIRECTION\n\nSpecify:\n- modern, high-end, creatively daring {{ $json.output.business_type }} aesthetic\n- controlled color usage with intentional contrast\n- polished lighting, depth, or graphic precision\n- campaign-level visual quality suitable for paid media\n\n--------------------------------\nOUTPUT FORMAT (STRICT JSON)\n\n{\n \"headline1\": \"\",\n \"headline2\": \"\",\n \"subheadline1\": \"\",\n \"subheadline2\": \"\",\n \"cta_text1\": \"\",\n \"cta_text2\": \"\",\n \"main_visual1\": \"\",\n \"layout_description1\": \"\",\n \"style_direction1\": \"\"\n}",
"options": {},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 2.2
},
{
"id": "ec43b0b3-dc29-41ae-a085-57d4245a7c3b",
"name": "Generate Ad Image",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"maxTries": 5,
"position": [
1344,
2384
],
"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 {{ $('Build Brand Insights').item.json.output.business_type }} value-proposition advertisement based strictly on the structured concept and text below.\\n\\nAD CONCEPT SOURCE:\\nMain visual: {{ $json.output.main_visual1 }}\\nLayout: {{ $json.output.layout_description1 }}\\nStyle direction: {{ $json.output.style_direction1 }}\\n\\nDISPLAYED TEXT CONTENT (use these exact words, but do not print labels like \\\"headline\\\" or \\\"CTA\\\"):\\nPrimary headline text: {{ $json.output.headline1 }}\\nSupporting subheadline text: {{ $json.output.subheadline1 }}\\nCall-to-action text: {{ $json.output.cta_text1 }}\\n\\nTEXT-FIRST COMPOSITION:\\n- the layout must be designed around the headline as the primary anchor\\n- headline must be dominant and clearly readable at first glance\\n- subheadline must be smaller and support the headline\\n- CTA must be a distinct button or label\\n- maintain generous whitespace and clean spacing\\n- never hide, crop, distort, or omit any text\\n\\nASSET USAGE:\\n- always include the provided asset and integrate it according to the concept\\n- if the asset is a UI/dashboard, it must be clearly visible, readable, and occupy the primary focal area\\n- do not blur, heavily crop, tilt, or obscure the UI\\n\\nANTI-AI LOOK STYLE RULES:\\n- avoid glossy 3D, plastic materials, neon glow, sci-fi lighting, excessive reflections, or overdone gradients\\n- prefer flat or softly shaded illustration, editorial product-marketing visuals\\n- restrained lighting, calm contrast, minimal visual noise\\nKeep the background bright, clean, and uncluttered.\"\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\": [\"image\", \"text\"],\n \"stream\": false\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "predefinedCredentialType",
"nodeCredentialType": "openRouterApi"
},
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 4.2
},
{
"id": "38a86e1a-e3d5-4a5f-9e3f-063d32bf120b",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-16,
1552
],
"parameters": {
"color": 5,
"width": 3232,
"height": 608,
"content": "## 2. Homepage fetch + page selection\n\n**Double click** to edit me.\n\n### What happens here\n\n- The homepage is fetched first\n- Navigation links are extracted\n- AI selects a few useful internal pages likely to contain strong marketing input\n- Those pages are then fetched and converted into readable text\n\n### Why this matters\n\nA homepage usually is not enough on its own.\n\nThis step expands the source material with richer copy from pages like:\n- features\n- pricing\n- solutions\n- customers\n- use cases\n\n### Output\n\n- selected internal pages\n- extracted website text\n- broader brand and product context"
},
"typeVersion": 1
},
{
"id": "6da9ac68-640c-4059-9372-8c40559d14d3",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-16,
2176
],
"parameters": {
"color": 6,
"width": 3232,
"height": 688,
"content": "## 3. Insights, ad concept + image generation\n\n**Double click** to edit me.\n\n### What happens here\n\n- Website text is cleaned and combined into one usable input\n- AI extracts structured brand insights such as:\n - product summary\n - customer group\n - problems\n - key benefits\n - brand voice\n\n- A creative ad concept is then generated:\n - headline\n - subheadline\n - CTA\n - visual direction\n - layout direction\n\n- Finally, the image model generates the ad and exports the result\n\n### Why this matters\n\nThis is where raw website content becomes:\n1. **strategy**\n2. **creative direction**\n3. **final ad output**\n\n### Output\n\n- structured brand insights\n- final ad concept\n- generated ad image\n- optional exported file"
},
"typeVersion": 1
},
{
"id": "c6862860-afcd-4adb-a90d-f052a77525dc",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"color": 4,
"width": 656,
"content": "## What this workflow does\n\nThis workflow turns a **website + logo + product image** into a ready ad concept and generated creative.\n\nIt pulls useful context from the site, figures out what the uploaded visual is, builds messaging and creative direction with Claude, then generates the final image."
},
"typeVersion": 1
},
{
"id": "b2ada541-e45e-476e-9b4a-754c7969401b",
"name": "Anthropic Chat Model2",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
1296,
1760
],
"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",
"executionOrder": "v1"
},
"versionId": "7ce6cf7f-cb13-4fbb-9cfa-34cdea29618a",
"connections": {
"If": {
"main": [
[
{
"node": "User Asset Base64",
"type": "main",
"index": 0
}
],
[
{
"node": "User Asset Base",
"type": "main",
"index": 0
}
]
]
},
"HTML": {
"main": [
[
{
"node": "Extract Sub-Website Copy",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Base inputs",
"type": "main",
"index": 0
}
]
]
},
"Merge1": {
"main": [
[
{
"node": "Aggregate1",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Map websites",
"type": "main",
"index": 0
}
]
]
},
"Aggregate1": {
"main": [
[
{
"node": "Clean text",
"type": "main",
"index": 0
}
]
]
},
"Aggregate2": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 1
}
]
]
},
"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
}
]
]
},
"Map websites": {
"main": [
[
{
"node": "Get website (text)",
"type": "main",
"index": 0
}
]
]
},
"Text extract": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 0
}
]
]
},
"Text extract1": {
"main": [
[
{
"node": "Aggregate2",
"type": "main",
"index": 0
}
]
]
},
"Fetch Homepage": {
"main": [
[
{
"node": "HTML",
"type": "main",
"index": 0
},
{
"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
}
]
]
},
"Get website (text)": {
"main": [
[
{
"node": "Text extract1",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model": {
"ai_languageModel": [
[
{
"node": "Extract Sub-Website Copy",
"type": "ai_languageModel",
"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
}
]
]
},
"Extract Sub-Website Copy": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Extract Sub-Website Copy",
"type": "ai_outputParser",
"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 marketers, founders, agencies, and content teams who want to generate static ad creatives faster from minimal brand input.
Source: https://n8n.io/workflows/15236/ — 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.
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 workflow is designed for ecommerce brands, marketers, agencies, and content teams who want to generate static product ads faster from minimal product input.
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.