AutomationFlowsAI & RAG › Create Seo-optimized Blog Articles with Gpt-4o Mini's Multi-stage Generation

Create Seo-optimized Blog Articles with Gpt-4o Mini's Multi-stage Generation

ByPake.AI @pake-ai on n8n.io

This workflow converts a single topic into a full blog article through a structured multi-step process. Instead of generating everything in one pass, it breaks the task into clear stages to produce cleaner structure, better SEO consistency, and more predictable output quality.…

Event trigger★★★★☆ complexityAI-powered18 nodesOpenAI ChatOutput Parser StructuredAgentMemory Buffer Window
AI & RAG Trigger: Event Nodes: 18 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Agent → OpenAI Chat 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": "b8e73760-245e-4265-bbca-4b82f82b7758",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -224,
        96
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e0527391-e9fe-45c4-95f3-192a98690782",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        240,
        320
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ca7b3775-810c-4ab3-9d19-362e81c23e77",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        368,
        320
      ],
      "parameters": {
        "jsonSchemaExample": "{ \"topic\": \"string\", \"subtopics\": [ { \"subtopic\": \"string\", \"details\": \"string\" } ] } "
      },
      "typeVersion": 1.3
    },
    {
      "id": "8c7a681e-fc37-43e7-9f0b-99cbf75a106b",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        800,
        96
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "34aa06eb-a8ab-48c5-af40-dee391965b62",
      "name": "AI Agent1",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1024,
        96
      ],
      "parameters": {
        "text": "=The outline refers to parts of a conversation.\nThis is the article section that covers these topics:\n\nSubtopic: {{ $json.subtopic }}\nDetails: {{ $json.details }}\n\nWrite a maximum of 1 paragraph.\nDo not number any sections.\nInclude a lot of detail.\n\nMandatory Rules\n\n1. Do not add numbering in any part.\n2. Write with detail and dense information.\n3. Ensure more than 75 percent of sentences contain a maximum of 20 words to meet YOAST SEO readability standards.\n4. Ensure the keyword \"{{ $('Input Topic Plans').item.json.Keyword }}\" appears in the sentences.\n5. Use clear and active sentences.\n6. Use 1 or 2 transition words recognized by YOAST. Examples: so, therefore, however, besides that, then, after that, for example.\n7. Avoid emojis, excessive punctuation, and promotional style.\n8. Do not use em dashes to keep the writing natural and not AI generated.\n9. Write in {{ $('Input Topic Plans').item.json.Language }} Language",
        "options": {
          "systemMessage": "You are a wise expert writer who shares an abundance of detail and examples, covering niche subtopics and rarely known small details."
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "05a44cb4-15de-41a2-9a41-cca190feb4aa",
      "name": "OpenAI Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1040,
        320
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "gpt-4o-mini"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5bd8b8be-6dfe-4616-84f2-db71be3bf1fd",
      "name": "Aggregate",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1088,
        -208
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "be01bbe2-5cb6-41c7-842a-68dce304c87c",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        1168,
        320
      ],
      "parameters": {
        "sessionKey": "={{ $('Loop Over Items').item.json.details }}",
        "sessionIdType": "customKey"
      },
      "typeVersion": 1.3
    },
    {
      "id": "687db5eb-d6cd-4c2a-8d7d-555b346ee2d0",
      "name": "Create New Array",
      "type": "n8n-nodes-base.code",
      "position": [
        1376,
        224
      ],
      "parameters": {
        "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n  item.json.subtopic = $('Loop Over Items').first().json.subtopic\n}\n\nreturn $input.all();"
      },
      "typeVersion": 2
    },
    {
      "id": "2d2291b6-8818-40cd-99dd-8ea8a5044d30",
      "name": "JSON HTML",
      "type": "n8n-nodes-base.code",
      "position": [
        1376,
        -208
      ],
      "parameters": {
        "jsCode": "// Input contoh: { title, article: [{subtopic, output}, ...] }\nconst title = $('Generate Outline').first().json.output.topic;\nconst items = Array.isArray($input.first().json.data) ?  $input.first().json.data: [];\n\nconst norm = (v) => (v ?? '').toString().trim();\nconst para = (t) => t\n  .split(/\\n{2,}/).map(s => s.trim()).filter(Boolean)\n  .map(s => `<p>${s}</p>`).join('\\n');\n\nlet md = '';\nlet html = '';\n\n// 1) Item pertama: hanya output\nif (items[0]) {\n  const out0 = norm(items[0].output);\n  if (out0) {\n    md += `${out0}\\n\\n`;\n    html += para(out0) + '\\n\\n';\n  }\n}\n\n// 2) Sisanya: subtopic lalu output\nfor (let i = 1; i < items.length; i++) {\n  const st = norm(items[i].subtopic);\n  const out = norm(items[i].output);\n\n  if (st) {\n    md += `## ${st}\\n\\n`;\n    html += `<h2>${st}</h2>\\n`;\n  }\n  if (out) {\n    md += `${out}\\n\\n`;\n    html += para(out) + '\\n\\n';\n  }\n}\n\n// Optional: ringkas spasi\nmd = md.replace(/\\n{3,}/g, '\\n\\n').trim();\nhtml = html.replace(/\\n{3,}/g, '\\n\\n').trim();\n\n// Keluaran untuk node berikutnya (HTTP Request -> WordPress)\nreturn [\n  {\n    json: {\n      title,\n      content_markdown: md,\n      content_html: html,           // for Rest API\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "b77d1b0a-0252-499a-8b77-769a12fa291f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        -80
      ],
      "parameters": {
        "width": 336,
        "height": 560,
        "content": "## Article Generator SEO Friendly\n\n### How it works:\n\u2022 Generates a structured outline from your topic using an AI Agent.\n\u2022 Loops through each subtopic and expands it into a detailed, SEO-friendly paragraph.\n\u2022 Combines everything into two final outputs. A clean JSON object and a Markdown version.\n\u2022 Content is tested in Yoast SEO and achieves Good readability.\n\u2022 Uses GPT-4o Mini by default. Token usage is usually 2000 to 3000 depending on the number of outline items.\n\n### Set up steps\n\u2022 Prepare your OpenAI API Key.\n\u2022 Adjust the topic, outline count, language, and keyword as needed in teh *Edit Fields*.\n\u2022 Change the model anytime if you want different quality or token usage."
      },
      "typeVersion": 1
    },
    {
      "id": "e640a067-78a9-4256-a70e-b293677cbfa5",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        736,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 896,
        "height": 448,
        "content": "## 2. Loop the Outline and Generate Paragraph\nWe also using simple memory to make sure the loop still relevant"
      },
      "typeVersion": 1
    },
    {
      "id": "724d69a1-a553-48c6-a445-d92fbd423d6d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        -352
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 320,
        "content": "## 3.Result become JSON with Markdown and HTML format\nJust continue this nodes with your purpose"
      },
      "typeVersion": 1
    },
    {
      "id": "db82eca5-32b4-4435-a864-d0ccf9db7c81",
      "name": "Generate Outline",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        224,
        96
      ],
      "parameters": {
        "text": "=Write a creative outline max {{ $json[\"How many outline?\"] }} item on {{ $json.Topic }} in {{ $json.Language }} language. \n\nOutput a JSON object with the following structure: { \"topic\": \"string\", \"subtopics\": [ { \"subtopic\": \"string\", \"details\": \"string\" } ] } Start the subtopic with an Introduction and end with a Conclusion.",
        "options": {
          "systemMessage": "You are a wise expert writer who fluent with Bahasa Indonesia and has broad knowledge ranging from general overview to niche subtopics, including rarely known small details."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3
    },
    {
      "id": "ee209bbb-6bf5-4d6b-ae22-83aece5887d0",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        16
      ],
      "parameters": {
        "color": 7,
        "width": 752,
        "height": 448,
        "content": "## 1. Creating Outline"
      },
      "typeVersion": 1
    },
    {
      "id": "c13a47ac-8e53-4c71-ad7b-8896524a8938",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        -544
      ],
      "parameters": {
        "width": 336,
        "height": 400,
        "content": "## Workflow Creator Profile \u2013 Pake.AI\n\n**Pake.AI** is an AI Enabler from Indonesia, committed to helping creators, entrepreneurs, and businesses automate their operations through practical and accessible AI solutions.\n\nThis workflow is shared **for free** to support the community and accelerate AI adoption.\n\nIf you have any questions about this workflow or want to explore more automation tools, feel free to contact us:\n\n\ud83c\udf10 **https://pake.ai**\n"
      },
      "typeVersion": 1
    },
    {
      "id": "f6da2439-4e85-4fc4-b018-99fd12f61dae",
      "name": "Input Topic Plans",
      "type": "n8n-nodes-base.set",
      "position": [
        0,
        96
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "11ae2bc0-2188-4392-85b5-4c05afc2d7f4",
              "name": "Topic",
              "type": "string",
              "value": "Input your topic Here"
            },
            {
              "id": "6a4a8161-5dad-433d-9cb0-900377b8b66f",
              "name": "How many outline?",
              "type": "number",
              "value": 3
            },
            {
              "id": "1a9d9e94-7610-49aa-9a0e-703eebc34ee1",
              "name": "Language",
              "type": "string",
              "value": "Input the language here (ex: English/Indonesia/Arabic/etc)"
            },
            {
              "id": "345e7e1f-f980-4140-849c-4150b903ab9f",
              "name": "Keyword",
              "type": "string",
              "value": "Put your keyword here"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0bbbe751-95c1-413a-81a1-beb3163907ab",
      "name": "Get Subtopic Array (For Looping)",
      "type": "n8n-nodes-base.code",
      "position": [
        576,
        96
      ],
      "parameters": {
        "jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nreturn $input.first().json.output.subtopics"
      },
      "typeVersion": 2
    }
  ],
  "connections": {
    "AI Agent1": {
      "main": [
        [
          {
            "node": "Create New Array",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "JSON HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "AI Agent1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create New Array": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Outline": {
      "main": [
        [
          {
            "node": "Get Subtopic Array (For Looping)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Input Topic Plans": {
      "main": [
        [
          {
            "node": "Generate Outline",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Outline",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent1",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Generate Outline",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Get Subtopic Array (For Looping)": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Input Topic Plans",
            "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 converts a single topic into a full blog article through a structured multi-step process. Instead of generating everything in one pass, it breaks the task into clear stages to produce cleaner structure, better SEO consistency, and more predictable output quality.…

Source: https://n8n.io/workflows/10813/ — 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

Digital marketers, content creators, social media managers, and businesses who want to use AI marketing automation for YouTube Shorts without spending hours on production. This AI workflow helps anyon

OpenAI, HTTP Request, OpenAI Chat +7
AI & RAG

Unlock the Power of Language with Personalized AI Learning! MOTION TUTOR is a revolutionary AI-powered language learning platform that adapts to your progress and guides you from basic vocabulary to c

Agent, Airtable Tool, OpenAI Chat +6
AI & RAG

This automation is designed to help you generate AI-powered music tracks, cover art, and fully rendered music videos — all triggered from a simple Telegram chat and managed via Google Sheets.

OpenAI Chat, Memory Buffer Window, Output Parser Structured +11
AI & RAG

This workflow serves as a comprehensive "Workflow Nodes SEO & Documentation Generator". It uses AI to analyze, rename, and document n8n workflows, offering a streamlined way to optimize workflow reada

Form Trigger, n8n, Output Parser Autofixing +11
AI & RAG

Template Carnaval - time instagram. Uses toolWorkflow, lmChatOpenAi, memoryBufferWindow, agent. Event-driven trigger; 56 nodes.

Tool Workflow, OpenAI Chat, Memory Buffer Window +10