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
Market Nexus. Uses httpRequest, agent, outputParserStructured, lmChatGoogleGemini. Webhook trigger; 23 nodes.
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.