AutomationFlowsSocial Media › Create Data-driven SEO Content Briefs with AI Analysis of Serp Data Using…

Create Data-driven SEO Content Briefs with AI Analysis of Serp Data Using…

Original n8n title: Create Data-driven SEO Content Briefs with AI Analysis of Serp Data Using Bright Data

Byphil @phil on n8n.io

This workflow is your all-in-one AI Content Strategist, designed to generate comprehensive, data-driven content briefs by analyzing top-ranking competitors.

Chat trigger trigger★★★★☆ complexityAI-powered27 nodesChat Trigger@Brightdata/N8N Nodes BrightdataOpenRouter ChatChatOutput Parser StructuredChain LlmMemory Buffer Window
Social Media Trigger: Chat trigger Nodes: 27 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Chainllm → Chat 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 →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "ab8957e5-c78b-4fd7-b4f7-d4958449c8a2",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -576,
        32
      ],
      "parameters": {
        "public": true,
        "options": {
          "title": "SEO Content Strategist",
          "subtitle": "Generate a strategic content brief based on SERP analysis.",
          "responseMode": "responseNodes",
          "inputPlaceholder": "Enter your target keyword...",
          "loadPreviousSession": "memory"
        },
        "initialMessages": "Welcome.\nI am your AI Content Strategist. Provide a target keyword, and I will analyze the top 10 search results to generate a detailed content plan designed to outrank the competition."
      },
      "typeVersion": 1.3
    },
    {
      "id": "d41436d3-0b50-456f-aa04-53dd2ea58460",
      "name": "extract url",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        32
      ],
      "parameters": {
        "jsCode": "// Extract each result from the 'organic' array of each input item\n// and transform it into a new individual n8n item.\nreturn items.flatMap((item, index) => {\n\u00a0 // Use optional chaining (?.) to safely access 'organic'.\n\u00a0 const organicResults = item.json?.organic;\n\n\u00a0 // Check if 'organicResults' is an array before proceeding.\n\u00a0 if (!Array.isArray(organicResults)) {\n\u00a0 \u00a0 return []; // Return an empty array if 'organic' does not exist or is not an array.\n\u00a0 }\n\u00a0\u00a0\n\u00a0 // For each result in 'organic', create a new n8n item.\n\u00a0 return organicResults.map(result => ({\n\u00a0 \u00a0 json: result,\n\u00a0 \u00a0 // Link this output item to the original input item for traceability.\n\u00a0 \u00a0 pairedItem: {\n\u00a0 \u00a0 \u00a0 item: index\n\u00a0 \u00a0 }\n\u00a0 }));\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "181ecd07-25a0-4e9a-b35d-87c80c0182ea",
      "name": "Google SERP",
      "type": "@brightdata/n8n-nodes-brightdata.brightData",
      "position": [
        32,
        32
      ],
      "parameters": {
        "url": "=https://www.google.com/search?q={{ encodeURIComponent($json.chatInput) }}&num=10&brd_json=1",
        "zone": {
          "__rl": true,
          "mode": "list",
          "value": "serp_api1",
          "cachedResultName": "serp_api1"
        },
        "country": {
          "__rl": true,
          "mode": "list",
          "value": "us"
        },
        "requestOptions": {}
      },
      "credentials": {
        "brightdataApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b66a2603-0db5-43c7-a57b-6ae2f8e1b17e",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        912,
        32
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "bed27461-483e-4d4b-9fe0-a668ccb18259",
      "name": "Limit",
      "type": "n8n-nodes-base.limit",
      "disabled": true,
      "position": [
        688,
        32
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e9880005-8d30-4a46-a3d5-90c442c8b942",
      "name": "Aggregate",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        1152,
        -480
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "b13a5f96-aa70-4415-85aa-58ad02cd21ba",
      "name": "OpenRouter Chat Model1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        2112,
        -272
      ],
      "parameters": {
        "model": "openai/gpt-5-nano",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d73b8962-d7e3-4eaa-9154-d71b116f2d23",
      "name": "Respond to Chat",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        464,
        32
      ],
      "parameters": {
        "message": "Starting content extraction from top-ranking pages.",
        "options": {
          "memoryConnection": false
        },
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "2a5b0dac-6c8f-4b78-8721-32f5df9a75e8",
      "name": "Respond to Chat1",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        -192,
        32
      ],
      "parameters": {
        "message": "=Processing: Analyzing top 10 Google results for \"{{ $json.chatInput }}\". ",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "7e8b299d-34c7-4c22-ab0f-f8128c45e10c",
      "name": "Respond to Chat2",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        2544,
        480
      ],
      "parameters": {
        "message": "=Scraped {{ $json.url }}",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "772b40b4-6cc8-469c-83fa-0a05551bea78",
      "name": "Respond to Chat3",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        1360,
        -544
      ],
      "parameters": {
        "message": "All data collected. Synthesizing insights and generating your strategic content plan. ",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "0416ad60-aa54-4aff-b9c8-c59aaae1e9ad",
      "name": "Respond to Chat4",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        2432,
        -592
      ],
      "parameters": {
        "message": "={{ $json.text }}",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "cd673b53-9f62-4fa4-9cfc-e627b2e35b93",
      "name": "OpenRouter Chat Model2",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1456,
        -368
      ],
      "parameters": {
        "model": "openai/gpt-4o",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fb4c0751-9093-4527-b605-4586d2eaa158",
      "name": "Respond to Chat5",
      "type": "@n8n/n8n-nodes-langchain.chat",
      "position": [
        1872,
        -400
      ],
      "parameters": {
        "message": "={{ $json.text }}",
        "options": {},
        "waitUserReply": false
      },
      "typeVersion": 1
    },
    {
      "id": "85795099-7b23-478a-8ec1-9a971a583519",
      "name": "Access and extract data from a specific URL",
      "type": "@brightdata/n8n-nodes-brightdata.brightData",
      "position": [
        1200,
        192
      ],
      "parameters": {
        "url": "={{ $json.link }}",
        "zone": {
          "__rl": true,
          "mode": "list",
          "value": "web_unlocker1",
          "cachedResultName": "web_unlocker1"
        },
        "country": {
          "__rl": true,
          "mode": "list",
          "value": "us"
        },
        "requestOptions": {}
      },
      "credentials": {
        "brightdataApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "3725cd69-396b-477d-9850-eaee8478ded2",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1728,
        448
      ],
      "parameters": {
        "model": "openai/gpt-5-nano",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "05d95321-57a7-46ef-bdf2-63fc38eaa0bc",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1904,
        464
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"summary\": \"This is a summary of the analyzed content.\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "f1c56a78-8157-4be9-acd8-8004e4815cd4",
      "name": "analyse site",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1744,
        256
      ],
      "parameters": {
        "text": "={{ $json.cleanedHtml }}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "You are an SEO expert:|Output in JSON without any comments** summary: summarize this page."
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "e73d1f30-9b67-4f5f-8b60-555d21adf79f",
      "name": "extract html1",
      "type": "n8n-nodes-base.code",
      "position": [
        1792,
        96
      ],
      "parameters": {
        "jsCode": "// Extracts title, description, headings, and counts words from the HTML content.\n// Reads from the 'cleanedHtml' property provided by the previous node.\n\nconst results = [];\nfor (let i = 0; i < items.length; i++) {\n\u00a0 const html = items[i].json.cleanedHtml;\n\n\u00a0 if (typeof html !== 'string') {\n\u00a0 \u00a0 results.push({\n\u00a0 \u00a0 \u00a0 json: {\n\u00a0 \u00a0 \u00a0 \u00a0 error: \"The 'cleanedHtml' field is missing or invalid.\"\n\u00a0 \u00a0 \u00a0 },\n\u00a0 \u00a0 \u00a0 pairedItem: i\n\u00a0 \u00a0 });\n\u00a0 \u00a0 continue;\n\u00a0 }\n\n\u00a0 // Existing extractions\n\u00a0 const titleMatch = html.match(/<title>(.*?)<\\/title>/i);\n\u00a0 const title = titleMatch ? titleMatch[1].trim() : null;\n\n\u00a0 const descriptionMatch = html.match(/<meta\\s+name=\"description\"\\s+content=\"(.*?)\"/i);\n\u00a0 const description = descriptionMatch ? descriptionMatch[1].trim() : null;\n\n\u00a0 const headingRegex = /<h([1-6])[^>]*>(.*?)<\\/h\\1>/gi;\n\u00a0 const headings = Array.from(html.matchAll(headingRegex)).map(match => ({\n\u00a0 \u00a0 level: parseInt(match[1], 10),\n\u00a0 \u00a0 text: match[2].trim()\n\u00a0 }));\n\n\u00a0 // Addition: Word count\n\u00a0 // Remove all HTML tags to keep only the text.\n\u00a0 const textContent = html.replace(/<[^>]*>/g, ' ');\n\u00a0 // Replace multiple spaces with a single one, trim leading/trailing spaces, then split by space.\n\u00a0 const words = textContent.replace(/\\s+/g, ' ').trim().split(' ');\n\u00a0 // Filter out empty elements that might result from the split.\n\u00a0 const wordCount = words.filter(word => word.length > 0).length;\n\n\u00a0 results.push({\n\u00a0 \u00a0 json: {\n\u00a0 \u00a0 \u00a0 title,\n\u00a0 \u00a0 \u00a0 description,\n\u00a0 \u00a0 \u00a0 headings,\n\u00a0 \u00a0 \u00a0 wordCount // Add the word count result\n\u00a0 \u00a0 },\n\u00a0 \u00a0 pairedItem: i\n\u00a0 });\n}\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "b36a1655-500e-45ff-8c66-6e3918d3bf91",
      "name": "clean html",
      "type": "n8n-nodes-base.code",
      "position": [
        1408,
        192
      ],
      "parameters": {
        "jsCode": "// Applies a series of regex cleaning rules to HTML content,\n// including the removal of <svg>, <nav>, <ul>, and <li> tags.\nconst cleaningRules = [\n\u00a0 { regex: /<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, replacement: '' },\n\u00a0 { regex: /<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, replacement: '' },\n\u00a0 { regex: /<svg\\b[^>]*>[\\s\\S]*?<\\/svg>/gi, replacement: '' },\n\u00a0 { regex: /<nav\\b[^>]*>[\\s\\S]*?<\\/nav>/gi, replacement: '' },\n\u00a0 // Removes <ul> and <li> tags but keeps their text content.\n\u00a0 { regex: /<\\/?(ul|li)[^>]*>/gi, replacement: '' },\n\u00a0 { regex: /\\s+(class|id|style|for|tabindex|aria-[\\w-]+|data-[\\w-]+)\\s*=\\s*(?:'[^']*'|\"[^\"]*\")/gi, replacement: '' },\n\u00a0 { regex: />\\s+</g, replacement: '><' },\n\u00a0 { regex: /(\\r\\n|\\n|\\r){2,}/g, replacement: '\\n' },\n\u00a0 { regex: /[ \\t]{2,}/g, replacement: ' ' }\n];\n\nreturn items.map((item, i) => {\n\u00a0 // Looks for HTML content in item.json.data or directly in item.json.\n\u00a0 const htmlContent = String(item.json.data || item.json || '');\n\n\u00a0 if (typeof htmlContent !== 'string' || htmlContent.length === 0) {\n\u00a0 \u00a0 return {\n\u00a0 \u00a0 \u00a0 json: { \"cleanedHtml\": \"\" },\n\u00a0 \u00a0 \u00a0 pairedItem: i\n\u00a0 \u00a0 };\n\u00a0 }\n\n\u00a0 // Sequentially applies each cleaning rule to the HTML content.\n\u00a0 const cleanedHtml = cleaningRules.reduce(\n\u00a0 \u00a0 (currentHtml, rule) => currentHtml.replace(rule.regex, rule.replacement),\n\u00a0 \u00a0 htmlContent\n\u00a0 ).trim();\n\n\u00a0 // Returns the structured data object for n8n.\n\u00a0 return {\n\u00a0 \u00a0 json: {\n\u00a0 \u00a0 \u00a0 \"cleanedHtml\": cleanedHtml\n\u00a0 \u00a0 },\n\u00a0 \u00a0 pairedItem: i // Links this output item to its corresponding input item.\n\u00a0 };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "cd6100c1-65ec-4772-9619-784b307b6c9f",
      "name": "url",
      "type": "n8n-nodes-base.set",
      "position": [
        1776,
        -80
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "19fbb0af-21ad-42bd-9f27-5504ae101a21",
              "name": "url",
              "type": "string",
              "value": "={{ $json.link }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "687c6627-7259-4f12-a523-8ae065d4e1c7",
      "name": "Merge1",
      "type": "n8n-nodes-base.merge",
      "position": [
        2240,
        48
      ],
      "parameters": {
        "numberInputs": 3
      },
      "typeVersion": 3.2
    },
    {
      "id": "0bf5c3d4-552a-445a-a624-d00fe0879c23",
      "name": "Structured Output Parser1",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1712,
        -352
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"search_intent\": {\n    \"primary_intent\": \"A single word describing the intent: Informational, Commercial, Navigational, or Transactional.\",\n    \"description\": \"A brief explanation of what the user is trying to find or accomplish based on the SERP analysis.\"\n  },\n  \"global_intent\": \"A high-level statement about the new article's strategic goal. Example: 'To create the definitive guide on [Main Topic], addressing key user questions from beginner to advanced levels.'\",\n  \"must_cover_topics\": [\n    {\n      \"title\": \"The title of a core topic that must be included.\",\n      \"reasoning\": \"A brief explanation of why this topic is essential, referencing its prevalence in the SERP data.\"\n    }\n  ],\n  \"differentiation_suggestions\": [\n    {\n      \"suggestion\": \"A specific, actionable suggestion for content that will differentiate the article.\",\n      \"reasoning\": \"Explain why this suggestion addresses a content gap or provides unique value compared to the current top results.\"\n    }\n  ],\n  \"suggested_h2_outline\": [\n      {\n          \"h2_title\": \"What is [Main Keyword]?\",\n          \"description\": \"Define the main keyword and explain its core concepts. This section should address the fundamental 'what is' question for beginners.\"\n      },\n      {\n          \"h2_title\": \"Why is [Related Concept] Important?\",\n          \"description\": \"Explain the significance or benefits of a core concept related to the main keyword, establishing its value for the reader.\"\n      },\n      {\n          \"h2_title\": \"How to Get Started with [Main Keyword]\",\n          \"description\": \"Provide a step-by-step guide or a list of initial actions a user should take. This addresses the practical application of the topic.\"\n      },\n      {\n          \"h2_title\": \"Comparing [Option A] vs. [Option B]\",\n          \"description\": \"Present a comparison of common methods, tools, or options related to the main keyword. This helps users make informed decisions.\"\n      }\n  ]\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "5d12238d-0f79-4015-8c10-464c6a751f42",
      "name": "Analysis",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "onError": "continueErrorOutput",
      "position": [
        1568,
        -560
      ],
      "parameters": {
        "text": "=target keyword : {{ $('When chat message received').item.json.chatInput }}\n\nserp synthesis:\n{{ $items(\"Google SERP\").map(item => JSON.stringify(item.json, null, 2)).join('\\n\\n---\\n\\n') }}\n\ntop 10 pages extract:\n{{ $items(\"Aggregate\").map(item => JSON.stringify(item.json, null, 2)).join('\\n\\n---\\n\\n') }}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=You are a world-class SEO Content Strategist and data analyst.\nYou have been provided with a JSON object containing scraped data (titles, meta descriptions, summaries, headings) from the top Google results for a given keyword.\n\nYour mission is to synthesize this raw data into a strategic insight document. You must analyze the data as a whole to find patterns, core topics, and competitive gaps, and then structure these findings into a logical article outline.\n\n### YOUR TASK\nBased on the raw data provided above, generate a structured insight report. Follow these analytical steps:\n1.  **Analyze Search Intent**: From the titles and summaries, determine the primary user intent (e.g., informational, commercial, navigational, transactional) and describe what the user wants to accomplish.\n2.  **Define Global Intent**: Based on the analysis, formulate a high-level strategic goal for a new piece of content on this topic.\n3.  **Identify Core Topics**: Find the recurring high-value topics, entities, and questions that are common across most top-ranking articles. These are the \"must-have\" subjects to cover.\n4.  **Detect Differentiation Opportunities**: Identify questions or subtopics that are poorly covered, only mentioned by one or two articles, or are completely missed. These are the opportunities to add unique value and stand out.\n5.  **Propose an H2 Outline**: Consolidate the core topics and differentiation opportunities into a logical sequence of H2 headings for the article.\n\n### OUTPUT FORMAT\nYour output MUST be a single, valid JSON object and nothing else. Do not add any commentary or explanations. The JSON object must adhere strictly to the following structure:\n\n{\n  \"search_intent\": {\n    \"primary_intent\": \"A single word describing the intent: Informational, Commercial, Navigational, or Transactional.\",\n    \"description\": \"A brief explanation of what the user is trying to find or accomplish based on the SERP analysis.\"\n  },\n  \"global_intent\": \"A high-level statement about the new article's strategic goal. Example: 'To create the definitive guide on [Main Topic], addressing key user questions from beginner to advanced levels.'\",\n  \"must_cover_topics\": [\n    {\n      \"title\": \"The title of a core topic that must be included.\",\n      \"reasoning\": \"A brief explanation of why this topic is essential, referencing its prevalence in the SERP data.\"\n    }\n  ],\n  \"differentiation_suggestions\": [\n    {\n      \"suggestion\": \"A specific, actionable suggestion for content that will differentiate the article.\",\n      \"reasoning\": \"Explain why this suggestion addresses a content gap or provides unique value compared to the current top results.\"\n    }\n  ],\n  \"suggested_h2_outline\": [\n      {\n          \"h2_title\": \"What is [Main Keyword]?\",\n          \"description\": \"Define the main keyword and explain its core concepts. This section should address the fundamental 'what is' question for beginners.\"\n      },\n      {\n          \"h2_title\": \"Why is [Related Concept] Important?\",\n          \"description\": \"Explain the significance or benefits of a core concept related to the main keyword, establishing its value for the reader.\"\n      },\n      {\n          \"h2_title\": \"How to Get Started with [Main Keyword]\",\n          \"description\": \"Provide a step-by-step guide or a list of initial actions a user should take. This addresses the practical application of the topic.\"\n      },\n      {\n          \"h2_title\": \"Comparing [Option A] vs. [Option B]\",\n          \"description\": \"Present a comparison of common methods, tools, or options related to the main keyword. This helps users make informed decisions.\"\n      }\n  ]\n}"
            }
          ]
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.7
    },
    {
      "id": "8ab5bac7-64e4-405a-b44c-2489c6edba54",
      "name": "Format Output",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "onError": "continueErrorOutput",
      "position": [
        2048,
        -592
      ],
      "parameters": {
        "text": "=targeted Keyword: {{ $('When chat message received').item.json.chatInput }}\n\nAnalysis:\n{{ $items(\"Analysis\").map(item => JSON.stringify(item.json, null, 2)).join('\\n\\n---\\n\\n') }}\n{{$json}}",
        "batching": {},
        "messages": {
          "messageValues": [
            {
              "message": "=Your objective is to analyze the provided JSON data and generate a structured summary in English, formatted using Markdown.\n\nStrictly adhere to the following structure and formatting rules for the output:\n\nMain Title: Start with a level 1 Markdown heading: # Content Strategy Analysis\n\nSearch Intent Section:\n\nCreate a level 2 heading: ## Search Intent\n\nBelow it, create an unordered list with the following items, extracted directly from the JSON:\n\nThe value of search_intent.primary_intent.\n\nThe value of search_intent.description.\n\nThe value of global_intent.\n\nMust-Cover Topics Section:\n\nCreate a level 2 heading: ## Must-Cover Topics\n\nBelow it, iterate through the must_cover_topics array. For each object in the array, create a list item formatted as: **[title]:** [reasoning]\n\nDifferentiation Suggestions Section:\n\nCreate a level 2 heading: ## Differentiation Suggestions\n\nBelow it, iterate through the differentiation_suggestions array. For each object in the array, create a list item formatted as: **[suggestion]:** [reasoning]\n\nSuggested Outline Section:\n\nCreate a level 2 heading: ## Suggested H2 Outline\n\nBelow it, iterate through the suggested_h2_outline array. For each object in the array, create a list item formatted as: **[h2_title]:** [description]\n\nDo not include any introductory or concluding phrases. The output must only contain the formatted analysis based on the JSON."
            }
          ]
        },
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "25288223-d6f6-469b-aa3c-55506628b184",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -512,
        -400
      ],
      "parameters": {
        "width": 560,
        "height": 352,
        "content": "# SEO content Planner\n\n **Google SERP Analysis**  \n   The [n8n](https://n8n.partnerlinks.io/build) workflow retrieves the **top 10 Google search results** for a given keyword using Bright Data.  \n   \ud83d\udc49 Get your free Bright Data API key here: [https://get.brightdata.com/scrap](https://get.brightdata.com/scrap)\n\n **Content Extraction & Cleaning**  \n   It scrapes each result, cleans the HTML, and extracts structured data such as titles, meta descriptions, headings, and word count for analysis.\n\n **Strategic Content Plan Generation**  \n   AI models analyze the scraped data to determine search intent, identify essential topics, detect content gaps, and produce a strategic H2 outline for SEO content planning."
      },
      "typeVersion": 1
    },
    {
      "id": "13d5d113-00cb-4cb9-8022-62c3629fd599",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -576,
        240
      ],
      "parameters": {},
      "typeVersion": 1.3
    }
  ],
  "connections": {
    "url": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge1": {
      "main": [
        [
          {
            "node": "Respond to Chat2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analysis": {
      "main": [
        [
          {
            "node": "Format Output",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Chat5",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "Respond to Chat3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "clean html": {
      "main": [
        [
          {
            "node": "analyse site",
            "type": "main",
            "index": 0
          },
          {
            "node": "extract html1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google SERP": {
      "main": [
        [
          {
            "node": "extract url",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "extract url": {
      "main": [
        [
          {
            "node": "Respond to Chat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "analyse site": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Format Output": {
      "main": [
        [
          {
            "node": "Respond to Chat4",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond to Chat4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "When chat message received",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "extract html1": {
      "main": [
        [
          {
            "node": "Merge1",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Access and extract data from a specific URL",
            "type": "main",
            "index": 0
          },
          {
            "node": "url",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Chat": {
      "main": [
        [
          {
            "node": "Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Chat1": {
      "main": [
        [
          {
            "node": "Google SERP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Chat2": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Respond to Chat3": {
      "main": [
        [
          {
            "node": "Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "analyse site",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Format Output",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "Analysis",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "analyse site",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser1": {
      "ai_outputParser": [
        [
          {
            "node": "Analysis",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Respond to Chat1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Access and extract data from a specific URL": {
      "main": [
        [
          {
            "node": "clean html",
            "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 is your all-in-one AI Content Strategist, designed to generate comprehensive, data-driven content briefs by analyzing top-ranking competitors.

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

More Social Media workflows → · Browse all categories →

Related workflows

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

Social Media

This template is for learners, researchers, students and professionals who want to quickly capture the essence of a YouTube video.

Chat Trigger, HTTP Request, Chain Llm +2
Social Media

This workflow is for content creators, marketers, agencies, coaches, and businesses who want to maximize their YouTube content ROI by automatically generating multiple content assets from single video

Output Parser Structured, Chain Llm, OpenRouter Chat +2
Social Media

🧠 Reddit MVP Generator – Auto-Generate Startup Ideas from Real User Pain Points The Reddit MVP Generator is a fully automated business idea mining system built in n8n. It scans trending posts and user

Reddit, OpenRouter Chat, Output Parser Structured +3
Social Media

Earlier this year, as I got more involved with n8n, I committed to helping users on our community forums and the n8n subreddit. The volume of questions was growing, and I found it was a real challenge

Output Parser Structured, HTTP Request, Text Classifier +4