AutomationFlowsAI & RAG › Generate Marketing Ad Banners with LINE and Gemini

Generate Marketing Ad Banners with LINE and Gemini

Original n8n title: Generate Marketing Ad Banners with Line, Gemini, and Nano Banana Pro

ByMasaki Go @pippi on n8n.io

This workflow creates high-quality, text-rich advertising banners from simple LINE messages.

Webhook trigger★★★★☆ complexityAI-powered16 nodesHTTP RequestGoogle GeminiAWS S3
AI & RAG Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #11205 — we link there as the canonical source.

This workflow follows the Googlegemini → HTTP Request 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 →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "5533972c-f840-4961-81a4-785762ef1a8b",
      "name": "Main Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1504,
        480
      ],
      "parameters": {
        "width": 350,
        "height": 596,
        "content": "# Instant Ad Banner Generator\n\nThis workflow generates professional marketing banners from a simple text description using **Gemini** (for prompt engineering) and **Nano Banana Pro** (for high-quality image generation).\n\n### How it works\n1. **Input:** Receives a product/concept via LINE.\n2. **Optimization:** Gemini creates a detailed marketing prompt.\n3. **Generation:** Submits job to Nano Banana Pro and polls for completion.\n4. **Delivery:** Hosts image on S3 and sends to LINE.\n\n### Setup Steps\n1. **Credentials:** Add LINE, Google Gemini, AWS S3, and Kie.ai (Header Auth).\n2. **S3:** Ensure your bucket has public read access.\n3. **Webhook:** Add the URL to LINE Developers console."
      },
      "typeVersion": 1
    },
    {
      "id": "93b12061-dd75-43b6-99e7-e56c22cfd58a",
      "name": "Check Job Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        272,
        608
      ],
      "parameters": {
        "url": "https://api.kie.ai/api/v1/jobs/recordInfo",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "taskId",
              "value": "={{ $json.data.taskId }}"
            },
            {
              "name": "recordId",
              "value": "={{ $json.data.recordId }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {}
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4b92ebb6-7294-4ee3-9353-829dc8485797",
      "name": "Sticky Note ",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1056,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 680,
        "height": 345,
        "content": "## 1. Receive & Refine\n1. Extract text from LINE webhook.\n2. Use Gemini to optimize prompt for Japanese marketing.\n3. Generate professional, marketing-focused image prompt."
      },
      "typeVersion": 1
    },
    {
      "id": "d988d7fb-355f-4c83-aaa9-7cfbfb568b58",
      "name": "Sticky Note 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -272,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 1260,
        "height": 345,
        "content": "## 2. Async Generation (Nano Banana)\n1. Submit task to Nano Banana Pro (via Kie API).\n2. Wait loop (10s) to allow processing.\n3. Check status and extract the final Image URL."
      },
      "typeVersion": 1
    },
    {
      "id": "d3a2aeb0-7802-4f47-ba67-43673ef0c675",
      "name": "Sticky Note 5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 420,
        "height": 345,
        "content": "## 3. Host & Deliver\n1. Download the generated image.\n2. Upload to AWS S3 (Public Read).\n3. Push the image back to the user via LINE."
      },
      "typeVersion": 1
    },
    {
      "id": "6c48da33-6903-4e33-aeba-f0a4acf8f90f",
      "name": "LINE Webhook1",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -992,
        608
      ],
      "parameters": {
        "path": "banner-v7158-2025",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 1
    },
    {
      "id": "59e827d9-884e-4541-af6a-79b5e511110e",
      "name": "Extract Data1",
      "type": "n8n-nodes-base.code",
      "position": [
        -800,
        608
      ],
      "parameters": {
        "jsCode": "// LINE Webhook parsing\nconst body = items[0].json.body;\n\nif (!body.events || !Array.isArray(body.events) || !body.events[0]) {\n  throw new Error(\"No LINE events found\");\n}\n\nconst event = body.events[0];\n\nreturn [\n  {\n    json: {\n      replyToken: event.replyToken,\n      userId: event.source.userId,\n      message: event.message.text,\n      timestamp: event.timestamp\n    }\n  }\n];"
      },
      "typeVersion": 1
    },
    {
      "id": "8176325c-3932-46e6-b444-b81983b65a1a",
      "name": "Optimize Prompt (Marketing)1",
      "type": "@n8n/n8n-nodes-langchain.googleGemini",
      "position": [
        -624,
        608
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "models/gemini-2.0-flash-lite",
          "cachedResultName": "models/gemini-2.0-flash-lite"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "\"You are an expert Marketing Creative Director for Japanese market.\\nThe user will send you details for an ad banner in Japanese (Product, Target Audience, Catch Copy).\\nYour goal is to write a highly detailed English prompt for Nano Banana Pro (Gemini 3 Pro Image).\\n\\nIMPORTANT RULES:\\n1. Analyze the target audience and suggest appropriate color palette, mood, and design style.\\n2. Describe the visual composition with clear space for text overlay.\\n3. Include the specific Japanese Catch Copy text, instructing to render it clearly and legibly.\\n4. Specify camera angle, lighting, product placement, and overall aesthetic.\\n5. Keep the prompt focused and under 500 characters for optimal generation.\\n6. Output ONLY the English prompt text, nothing else - no explanations, no meta-commentary.\\n7. NEVER use double quotes (\\\") in your response. Use 'single quotes' or [brackets] for emphasis instead.\\n\\nExample format:\\n'Professional product photography, [product description], featuring Japanese text [\u30ad\u30e3\u30c3\u30c1\u30b3\u30d4\u30fc] in bold modern font, [composition details], [lighting style], [color palette], negative space for additional text, high quality, 8K resolution'\\n\\nRemember: Output ONLY the prompt text, nothing before or after. NO DOUBLE QUOTES.\""
            },
            {
              "content": "={{ $json.message }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "afeff72b-2245-489b-b474-8890a6a0b519",
      "name": "Submit to Nano Banana Pro1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -48,
        608
      ],
      "parameters": {
        "url": "https://api.kie.ai/api/v1/jobs/createTask",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"nano-banana-pro\",\n  \"input\": {\n    \"prompt\": \"{{ $json.prompt }}\",\n    \"aspect_ratio\": \"1:1\",\n    \"resolution\": \"2K\",\n    \"output_format\": \"png\"\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "9acb497c-6dd9-416d-b7c0-d0d6ad88e83a",
      "name": "Wait1",
      "type": "n8n-nodes-base.wait",
      "position": [
        112,
        608
      ],
      "parameters": {
        "amount": 10
      },
      "typeVersion": 1.1
    },
    {
      "id": "6a134248-2a3a-4762-9301-901439a79dee",
      "name": "Wait for Generation1",
      "type": "n8n-nodes-base.wait",
      "position": [
        448,
        608
      ],
      "parameters": {
        "unit": "seconds",
        "amount": 10
      },
      "typeVersion": 1
    },
    {
      "id": "e76b16dd-a29a-4c68-a5e1-caa7131dfb59",
      "name": "Parse Result1",
      "type": "n8n-nodes-base.code",
      "position": [
        608,
        608
      ],
      "parameters": {
        "jsCode": "// Parse response and extract image URL\nconst response = items[0].json;\nconst data = Array.isArray(response) ? response[0] : response;\n\nif (data.code === 200 && data.data) {\n  const taskData = data.data;\n  \n  if (taskData.state === 'success') {\n    let imageUrl = null;\n    try {\n      const resultData = JSON.parse(taskData.resultJson);\n      const resultUrls = resultData.resultUrls || [];\n      if (resultUrls.length > 0) {\n        imageUrl = resultUrls[0];\n      }\n    } catch (e) {\n      throw new Error('Failed to parse resultJson');\n    }\n    \n    if (imageUrl) {\n      return [{\n        json: {\n          imageUrl: imageUrl,\n          taskId: taskData.taskId,\n          status: 'completed'\n        }\n      }];\n    }\n  } else if (taskData.state === 'fail') {\n    throw new Error(`Image generation failed: ${taskData.failMsg}`);\n  } else {\n    // Loop back if processing\n    return [{\n        json: { status: 'processing' }\n    }];\n  }\n}"
      },
      "typeVersion": 1
    },
    {
      "id": "a6645fa5-60f1-408c-8bad-a4e055a3a2f6",
      "name": "Download Image1",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        800,
        608
      ],
      "parameters": {
        "url": "={{ $json.imageUrl }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        }
      },
      "typeVersion": 4.1
    },
    {
      "id": "75005330-f777-42e3-8d26-4ccc31dbee8d",
      "name": "Upload to S",
      "type": "n8n-nodes-base.awsS3",
      "position": [
        1120,
        608
      ],
      "parameters": {
        "fileName": "={{ 'banner-' + Date.now() + '.png' }}",
        "operation": "upload",
        "bucketName": "banners-bot-v7158",
        "additionalFields": {}
      },
      "credentials": {
        "aws": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "1cdb695f-37cd-48a9-9aba-c3d59a401ec9",
      "name": "HTTP Request2",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1312,
        608
      ],
      "parameters": {
        "url": "https://api.line.me/v2/bot/message/reply",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n \"replyToken\": \"{{ $('LINE Webhook').item.json.body.events[0].replyToken }}\",\n  \"messages\": [\n    {\n      \"type\": \"image\",\n      \"originalContentUrl\": \"{{ $('Upload to S3').item.json.Location }}\",\n      \"previewImageUrl\": \"{{ $('Upload to S3').item.json.Location }}\"\n    }\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "009e3f6b-aabe-4516-8820-ceea578b31aa",
      "name": "Code1",
      "type": "n8n-nodes-base.code",
      "position": [
        -224,
        608
      ],
      "parameters": {
        "jsCode": "// Extract the actual prompt text from Gemini's response\nconst response = items[0].json;\n\nlet promptText = \"\";\n\n// Check if we have the content structure from Gemini\nif (response.content && response.content.parts && response.content.parts[0]) {\n  let text = response.content.parts[0].text;\n  \n  // Parse the JSON array if it's a string\n  try {\n    const parsed = JSON.parse(text);\n    // If it's an array, get the first element\n    if (Array.isArray(parsed) && parsed.length > 0) {\n      promptText = parsed[0];\n    } else if (typeof parsed === 'string') {\n      promptText = parsed;\n    } else {\n      promptText = text; // Use as is if not parseable\n    }\n  } catch (e) {\n    // If JSON parsing fails, clean the text manually\n    promptText = text\n      .replace(/^\\[|\\]$/g, '') // Remove brackets\n      .replace(/^[\"']|[\"']$/g, '') // Remove quotes\n      .replace(/\\\\n/g, '') // Remove newlines\n      .trim();\n  }\n}\n\n// Clean any remaining escape characters\npromptText = promptText.replace(/\\\\\"/g, '\"').trim();\n\nreturn [{\n  json: {\n    prompt: promptText,\n    userId: $('Extract Data').item.json.userId,\n    taskId: response.taskId || null\n  }\n}];"
      },
      "typeVersion": 2
    }
  ],
  "connections": {
    "Code1": {
      "main": [
        [
          {
            "node": "Submit to Nano Banana Pro1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait1": {
      "main": [
        [
          {
            "node": "Check Job Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload to S": {
      "main": [
        [
          {
            "node": "HTTP Request2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Data1": {
      "main": [
        [
          {
            "node": "Optimize Prompt (Marketing)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LINE Webhook1": {
      "main": [
        [
          {
            "node": "Extract Data1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Result1": {
      "main": [
        [
          {
            "node": "Download Image1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Image1": {
      "main": [
        [
          {
            "node": "Upload to S",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Job Status": {
      "main": [
        [
          {
            "node": "Wait for Generation1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Generation1": {
      "main": [
        [
          {
            "node": "Parse Result1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Submit to Nano Banana Pro1": {
      "main": [
        [
          {
            "node": "Wait1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Optimize Prompt (Marketing)1": {
      "main": [
        [
          {
            "node": "Code1",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow creates high-quality, text-rich advertising banners from simple LINE messages.

Source: https://n8n.io/workflows/11205/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow turns complex data or topics sent via LINE into beautiful, easy-to-understand Infographics.

Google Gemini, HTTP Request, AWS S3
AI & RAG

User Signup & Verification: The workflow starts when a user signs up. It generates a verification code and sends it via SMS using Twilio. Code Validation: The user replies with the code. The workflow

Postgres, HTTP Request, OpenAI +2
AI & RAG

This workflow automates the process of generating stylized product photos for e-commerce by combining real product shots with creative templates. It enables the creation of a complete set of images fo

Airtable, HTTP Request, Google Gemini
AI & RAG

How it works Runs on schedule (Monday-Friday at 9 AM) to automate lead generation Searches for companies on Google Maps by location and category Extracts owner information from company websites and im

HTTP Request, Anthropic, Google Gemini +3
AI & RAG

This workflow is designed for creators, designers, and automation builders who need to generate visually consistent images at scale. It is ideal for teams producing branded visuals, social media asset

HTTP Request, Google Sheets, Google Gemini +1