AutomationFlowsAI & RAG › AI SEO Agent for SERP Analysis

AI SEO Agent for SERP Analysis

Original n8n title: SEO Agent Serp

seo-agent-serp. Uses httpRequest, informationExtractor, lmChatOpenAi. Webhook trigger; 11 nodes.

Webhook trigger★★★★☆ complexityAI-powered11 nodesHTTP RequestInformation ExtractorOpenAI Chat
AI & RAG Trigger: Webhook Nodes: 11 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the HTTP Request → Informationextractor 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
{
  "name": "seo-agent-serp",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "seo-metadata-agent",
        "responseMode": "lastNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        128,
        -128
      ],
      "id": "f22a6b0e-ba56-4a9f-9bbd-19d3b5be1eef",
      "name": "Webhook"
    },
    {
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {
          "redirect": {
            "redirect": {}
          },
          "response": {
            "response": {
              "responseFormat": "text"
            }
          },
          "timeout": 10000
        }
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        576,
        16
      ],
      "id": "5561b68a-fcac-47f1-949c-e1ef9ab0e44a",
      "name": "HTTP Request"
    },
    {
      "parameters": {
        "operation": "extractHtmlContent",
        "extractionValues": {
          "values": [
            {
              "key": "title",
              "cssSelector": "title"
            },
            {
              "key": "description",
              "cssSelector": "meta[name=\"description\"]",
              "returnValue": "attribute",
              "attribute": "content"
            }
          ]
        },
        "options": {}
      },
      "id": "17e77bb9-a1f6-4df9-a065-deb164e2ec43",
      "name": "Extract Metadata",
      "type": "n8n-nodes-base.html",
      "typeVersion": 1.2,
      "position": [
        800,
        16
      ]
    },
    {
      "parameters": {
        "jsCode": "return [{\n  agent_input: {\n    primary_keyword: $json.keyword,\n    target_url: $json.url,\n\n    current_metadata: {\n      title: $json.title,\n      description: $json.description\n    },\n\n    top_competitors: $json.competitors.map((c, index) => ({\n      rank: index + 1,\n      title: c.title,\n      description: c.description,\n      source: c.source\n    })),\n\n    constraints: {\n      title_length_min: 50,\n      title_length_max: 60,\n      description_length_min: 140,\n      description_length_max: 160,\n      keyword_must_appear_in_title: true,\n      keyword_must_appear_in_description: true\n    }\n  }\n}];\n"
      },
      "id": "2b80f387-5ad5-474a-9cba-5549de0f1236",
      "name": "Compute Diagnostics",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1248,
        -128
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "combineBy": "combineByPosition",
        "numberInputs": 3,
        "options": {}
      },
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        1024,
        -144
      ],
      "id": "03346c90-308e-4c40-932d-2f7fae6bd8ca",
      "name": "Merge"
    },
    {
      "parameters": {
        "text": "=You are a senior e-commerce SEO strategist.\n\nPrimary keyword: \"{{$json.agent_input.primary_keyword}}\"\n\nCurrent metadata:\nTitle: {{$json.agent_input.current_metadata.title}}\nDescription: {{$json.agent_input.current_metadata.description}}\n\nTop 3 competitors:\n{{ JSON.stringify($json.agent_input.top_competitors, null, 2) }}\n\n---\n\nGenerate 3 improved SEO metadata variations.\n\nRequirements:\n- Title length: {{$json.agent_input.constraints.title_length_min}}\u2013{{$json.agent_input.constraints.title_length_max}} characters\n- Description length: {{$json.agent_input.constraints.description_length_min}}\u2013{{$json.agent_input.constraints.description_length_max}} characters\n- The exact phrase \"{{$json.agent_input.primary_keyword}}\" must appear naturally in BOTH title and description\n- Stay aligned with competitor messaging style\n- Do not copy competitors\n- Do not invent features not present in competitors or current metadata\n- Use professional title case formatting\n\nReturn strictly valid JSON:\n\n{\n  \"variations\": [\n    {\n      \"title\": \"...\",\n      \"description\": \"...\",\n      \"reason\": \"Brief explanation of improvement.\"\n    },\n    {\n      \"title\": \"...\",\n      \"description\": \"...\",\n      \"reason\": \"...\"\n    },\n    {\n      \"title\": \"...\",\n      \"description\": \"...\",\n      \"reason\": \"...\"\n    }\n  ]\n}\n",
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"variations\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"title\": { \"type\": \"string\" },\n          \"description\": { \"type\": \"string\" },\n          \"reasoning\": { \"type\": \"string\" }\n        },\n        \"required\": [\"title\", \"description\", \"reasoning\"]\n      },\n      \"minItems\": 3,\n      \"maxItems\": 3\n    }\n  },\n  \"required\": [\"variations\"]\n}\n",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.informationExtractor",
      "typeVersion": 1.2,
      "position": [
        1472,
        -128
      ],
      "id": "35b80b3c-1dfd-464b-a938-88365e7fbfbe",
      "name": "Information Extractor",
      "retryOnFail": false
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\n\nfor (const item of items) {\n  // Support both direct JSON and wrapped body\n  const payload = item.json.body ?? item.json;\n\n  const { url, keyword } = payload;\n\n  if (!url || typeof url !== \"string\") {\n    throw new Error(\"Missing or invalid 'url'\");\n  }\n\n  if (!keyword || typeof keyword !== \"string\") {\n    throw new Error(\"Missing or invalid 'keyword'\");\n  }\n\n  if (!url.startsWith(\"http\")) {\n    throw new Error(\"URL must start with http or https\");\n  }\n\n  // Normalize\n  item.json.url = url.trim();\n  item.json.keyword = keyword.trim().toLowerCase();\n}\n\nreturn items;\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        352,
        -128
      ],
      "id": "d46fb75f-26a6-43e9-af51-95e071b8d2e3",
      "name": "URL Validation"
    },
    {
      "parameters": {
        "url": "https://serpapi.com/search.json",
        "sendQuery": true,
        "specifyQuery": "json",
        "jsonQuery": "={\n  \"engine\": \"google\",\n  \"q\": \"{{$json.keyword}}\",\n  \"num\": 3,\n  \"api_key\": \"a40e68d03ac6d9b7b75a5b519f653aff2bc12145f11fb001ee8f0d56138df2d3\"\n}\n",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        576,
        -272
      ],
      "id": "c03aaeae-cc5b-40f4-90ae-aa3fbb3d510e",
      "name": "HTTP Request1"
    },
    {
      "parameters": {
        "jsCode": "const results = $json.organic_results.slice(0, 3);\n\nreturn [{\n  competitors: results.map(r => ({\n    title: r.title,\n    description: r.snippet,\n    source: r.source\n  }))\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        -272
      ],
      "id": "b55c6471-1237-423d-a7ee-4e6a054422c0",
      "name": "Code in JavaScript"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini"
        },
        "builtInTools": {},
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.3,
      "position": [
        1544,
        96
      ],
      "id": "f50c7cd5-174a-4333-81bd-dc50535e9c5b",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Support both possible shapes\nconst variations =\n  $json.variations ||\n  $json.output?.variations;\n\nif (!Array.isArray(variations)) {\n  throw new Error(\"variations must be an array\");\n}\n\nif (variations.length !== 3) {\n  throw new Error(\"Must return exactly 3 variations\");\n}\n\nfor (let i = 0; i < variations.length; i++) {\n  const v = variations[i];\n\n  if (typeof v !== \"object\") {\n    throw new Error(`Variation ${i + 1} is not an object`);\n  }\n\n  if (!v.title || !v.description) {\n    throw new Error(`Variation ${i + 1} missing title or description`);\n  }\n}\n\nreturn [{\n  variations\n}];\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1824,
        -128
      ],
      "id": "95941236-7c0c-447a-b2a1-b4a3794375d2",
      "name": "Code in JavaScript1"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "URL Validation",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Extract Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Metadata": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Compute Diagnostics": {
      "main": [
        [
          {
            "node": "Information Extractor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Compute Diagnostics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Information Extractor": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "URL Validation": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          },
          {
            "node": "HTTP Request1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "HTTP Request1": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Information Extractor",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false
  },
  "versionId": "16021e26-391e-41a3-9c78-b2e6d1e15e40",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "ND1gtCXsbKgn07Kz",
  "tags": []
}

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

seo-agent-serp. Uses httpRequest, informationExtractor, lmChatOpenAi. Webhook trigger; 11 nodes.

Source: https://github.com/arnftz/seo-metadata-agent/blob/f8ec3c8ea089f8b45ba6f0985f15ddb506c1d07a/n8n/seo-agent-serp.json — 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

leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.

Supabase, Gmail, Form Trigger +13
AI & RAG

This suite automates distinct aspects of real estate operations: incoming web lead qualification, scheduled/manual data research and content generation, and automated voice call outreach with lead qua

Agent, HTTP Request, OpenAI Chat +6
AI & RAG

Automate candidate evaluation from CV submission to interview booking. Perfect for HR teams and recruiters.

Airtable, HTTP Request, Information Extractor +6
AI & RAG

This workflow is designed for Finance teams, accounting professionals, and automation engineers.

Information Extractor, HTTP Request, Output Parser Structured +4
AI & RAG

🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.

OpenAI, HTTP Request, Form Trigger +7