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 →
{
"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.
openAiApi
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 →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.
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
Automate candidate evaluation from CV submission to interview booking. Perfect for HR teams and recruiters.
This workflow is designed for Finance teams, accounting professionals, and automation engineers.
🎯 Create viral TikToks, Shorts, Reels, podcasts, and ASMR videos in minutes — all on autopilot.