This workflow corresponds to n8n.io template #6057 — we link there as the canonical source.
This workflow follows the Agent → Chainllm 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 →
{
"id": "MuPWDOe5EdbAR9LG",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Powered SEO Blog Writer",
"tags": [],
"nodes": [
{
"id": "652b062c-6398-4627-81fb-1bdc68a17b4c",
"name": "When clicking \u2018Execute workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1952,
-576
],
"parameters": {},
"typeVersion": 1
},
{
"id": "3ba48a52-d664-4c9f-8f4c-05c942fd117f",
"name": "Pinecone Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
"position": [
208,
-672
],
"parameters": {
"mode": "insert",
"options": {
"pineconeNamespace": "DataPlace"
},
"pineconeIndex": {
"__rl": true,
"mode": "list",
"value": "seo-writer",
"cachedResultName": "seo-writer"
}
},
"credentials": {
"pineconeApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "121a1c3a-a056-403c-ad76-28a974e60d68",
"name": "Default Data Loader",
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"position": [
416,
-464
],
"parameters": {
"options": {},
"dataType": "binary"
},
"typeVersion": 1
},
{
"id": "6bd61074-309d-4675-afac-6d09c59fab80",
"name": "Recursive Character Text Splitter",
"type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
"position": [
304,
-336
],
"parameters": {
"options": {},
"chunkSize": 2000,
"chunkOverlap": 200
},
"typeVersion": 1
},
{
"id": "ca4c81af-45e5-4c37-bbdb-83cb0233f9e9",
"name": "When chat message received",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
-160,
16
],
"parameters": {
"options": {}
},
"typeVersion": 1.1
},
{
"id": "7db55dbe-d04e-4515-aab7-9ad6ef8db8b5",
"name": "Window Buffer Memory",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
560,
224
],
"parameters": {
"sessionKey": "={{ $('When chat message received').first().json.sessionId }}",
"sessionIdType": "customKey"
},
"typeVersion": 1.3
},
{
"id": "b6d0989d-fd3b-40e5-bcda-2999ea5da413",
"name": "AI Agent1",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
448,
16
],
"parameters": {
"text": "={{ $('When chat message received').first().json.chatInput }}",
"options": {
"systemMessage": "=Use the following context to answer the user's question.\n<context>\n{{\n$input.all()\n .map(item => item.json.document.pageContent)\n .join('\\n---\\n')\n}}\n</context>"
},
"promptType": "define"
},
"executeOnce": true,
"typeVersion": 1.7,
"alwaysOutputData": false
},
{
"id": "2f7a11a0-5c54-4b0d-885a-8a63fd1b6b1e",
"name": "Pinecone Vector Store3",
"type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
"position": [
64,
16
],
"parameters": {
"mode": "load",
"prompt": "={{ $json.chatInput }}",
"options": {
"pineconeNamespace": "DataPlace"
},
"pineconeIndex": {
"__rl": true,
"mode": "list",
"value": "seo-writer",
"cachedResultName": "seo-writer"
}
},
"credentials": {
"pineconeApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "e82c2c2a-bba2-48ae-a1f0-1b0dba7afe01",
"name": "Embeddings Google Gemini3",
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"position": [
160,
224
],
"parameters": {
"modelName": "models/embedding-001"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "759f3623-2ced-4741-b78d-69b3f7c02d89",
"name": "Google Gemini Chat Model3",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
400,
208
],
"parameters": {
"options": {},
"modelName": "models/gemini-1.5-flash"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "8a361dda-4cd9-482d-a34a-32d8510f71f4",
"name": "Aggregate",
"type": "n8n-nodes-base.aggregate",
"position": [
-288,
-672
],
"parameters": {
"include": "specifiedFields",
"options": {},
"aggregate": "aggregateAllItemData",
"fieldsToInclude": "markdown"
},
"typeVersion": 1
},
{
"id": "01690ab5-5abe-4b8b-8570-00231d565ace",
"name": "Convert to File",
"type": "n8n-nodes-base.convertToFile",
"position": [
-48,
-672
],
"parameters": {
"options": {},
"operation": "toText",
"sourceProperty": "data"
},
"typeVersion": 1.1
},
{
"id": "526e7a83-ef44-4147-877f-ee6b52f7546c",
"name": "Edit Fields1",
"type": "n8n-nodes-base.set",
"position": [
-1872,
-32
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "0290299d-10a4-40c0-8d41-5d0563f6cd3a",
"name": "Keywords",
"type": "string",
"value": "\"Scraping\", \"Google trends\""
},
{
"id": "541029b9-1400-4a10-a9cd-9f472af59986",
"name": "Search Intent",
"type": "string",
"value": "People searching to get tips on Scraping"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "ce2c1ddb-0dc3-48ef-9e7b-bf77b33837e4",
"name": "Basic LLM Chain1",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
-1424,
-32
],
"parameters": {
"text": "=I want to write a SEO optimized blog.\n\nKeywords I used: {{ $('Edit Fields1').item.json.Keywords }}\nSearch Intent: {{ $('Edit Fields1').item.json['Search Intent'] }}\nSerp data for the keywords:\n {{ JSON.stringify($json.organic_results) }}\n\nPlease suggest some more keywords that actually align with my search intent. Make use of serp tool for relevancy of keywords.",
"batching": {},
"promptType": "define"
},
"typeVersion": 1.7
},
{
"id": "12412d90-0f45-4054-b5c7-612b595478f2",
"name": "Google Gemini Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-1344,
192
],
"parameters": {
"options": {},
"modelName": "models/gemini-1.5-flash"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "089cdb6a-d1c0-41e2-a98d-78422d5fd7e8",
"name": "Markdown",
"type": "n8n-nodes-base.markdown",
"position": [
-1072,
-32
],
"parameters": {
"mode": "markdownToHtml",
"options": {},
"markdown": "={{ $json.text }}"
},
"typeVersion": 1
},
{
"id": "c2c4cba6-a9e2-4ff9-a183-3de51050c23d",
"name": "HTML",
"type": "n8n-nodes-base.html",
"position": [
-848,
-32
],
"parameters": {
"html": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\" />\n <title>Report Summary</title>\n <link href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap\" rel=\"stylesheet\">\n <style>\n body {\n margin: 0;\n padding: 0;\n font-family: 'Inter', sans-serif;\n background: #f4f6f8;\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 100vh;\n }\n\n .container {\n background-color: #ffffff;\n max-width: 600px;\n width: 90%;\n padding: 32px;\n border-radius: 16px;\n box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);\n text-align: center;\n }\n\n h1 {\n color: #ff6d5a;\n font-size: 28px;\n font-weight: 700;\n margin-bottom: 12px;\n }\n\n h2 {\n color: #606770;\n font-size: 20px;\n font-weight: 600;\n margin-bottom: 24px;\n }\n\n .content {\n color: #333;\n font-size: 16px;\n line-height: 1.6;\n white-space: pre-wrap;\n }\n\n @media (max-width: 480px) {\n .container {\n padding: 20px;\n }\n\n h1 {\n font-size: 24px;\n }\n\n h2 {\n font-size: 18px;\n }\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <h1>Data Report</h1>\n <h2>Processed via Automation</h2>\n <div class=\"content\">{{ $json.data }}</div>\n </div>\n\n <script>\n console.log(\"Hello World!\");\n </script>\n</body>\n</html>\n"
},
"typeVersion": 1.2
},
{
"id": "b0f2fd25-9fbc-4872-9d70-2d3b0cbcd98e",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-992,
-560
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "4cb63818-ffbf-4ffb-9de5-e7fc545befb8",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2000,
-752
],
"parameters": {
"width": 1560,
"height": 600,
"content": "## Scrape and Crawl Website for Knowledge Base"
},
"typeVersion": 1
},
{
"id": "c527d49a-5f98-4b7f-892f-f97cb34e6834",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
-752
],
"parameters": {
"color": 4,
"width": 1360,
"height": 600,
"content": "## Store data on Pinecone"
},
"typeVersion": 1
},
{
"id": "973723ff-d2a4-48c3-8ad4-1cefbee3316a",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2000,
-144
],
"parameters": {
"color": 5,
"width": 1560,
"height": 580,
"content": "## SERP Analysis using AI"
},
"typeVersion": 1
},
{
"id": "501829c1-94f9-4c25-aa49-02f85f693ccf",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
-144
],
"parameters": {
"color": 3,
"width": 1360,
"height": 580,
"content": "## Use the Knowledge Base to Create Blogs"
},
"typeVersion": 1
},
{
"id": "27e0ebab-f963-4dd4-ac09-776b899378a2",
"name": "Embeddings Google Gemini",
"type": "@n8n/n8n-nodes-langchain.embeddingsGoogleGemini",
"position": [
128,
-480
],
"parameters": {},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "320558ff-ce36-4085-989d-acafa693aec5",
"name": "Crawl all Blogs",
"type": "n8n-nodes-scrapeless.scrapeless",
"position": [
-1712,
-576
],
"parameters": {
"url": "https://www.scrapeless.com/en/blog",
"resource": "crawler",
"operation": "crawl",
"limitCrawlPages": 20
},
"credentials": {
"scrapelessApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "c8e29523-8555-4a6e-89c3-f3335e319914",
"name": "Parse content and extract information",
"type": "n8n-nodes-base.code",
"position": [
-1488,
-576
],
"parameters": {
"jsCode": "return items.map(item => {\n const md = $input.first().json['0'].markdown; \n\n if (typeof md !== 'string') {\n console.warn('Markdown content is not a string:', md);\n return {\n json: {\n title: '',\n mainContent: '',\n extractedLinks: [],\n error: 'Markdown content is not a string'\n }\n };\n }\n\n const articleTitleMatch = md.match(/^#\\s*(.*)/m);\n const title = articleTitleMatch ? articleTitleMatch[1].trim() : 'No Title Found';\n\n let mainContent = md.replace(/^#\\s*.*(\\r?\\n)+/, '').trim();\n\n const extractedLinks = [];\n // The negative lookahead `(?!#)` ensures '#' is not matched after the base URL,\n // or a more robust way is to specifically stop before the '#'\n const linkRegex = /\\[([^\\]]+)\\]\\((https?:\\/\\/[^\\s#)]+)\\)/g; \n let match;\n while ((match = linkRegex.exec(mainContent))) {\n extractedLinks.push({\n text: match[1].trim(),\n url: match[2].trim(),\n });\n }\n\n return {\n json: {\n title,\n mainContent,\n extractedLinks,\n },\n };\n});"
},
"typeVersion": 2
},
{
"id": "9b8e9ced-06e4-42e2-814c-43b8bc6a18d4",
"name": "Scrape detailed contents",
"type": "n8n-nodes-scrapeless.scrapeless",
"position": [
-704,
-480
],
"parameters": {
"url": "={{ $json.url }}",
"resource": "crawler"
},
"credentials": {
"scrapelessApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "8acec9c9-8844-4f97-a6dd-1cfaab35a16a",
"name": "Analyze target keywords on Google SERP",
"type": "n8n-nodes-scrapeless.scrapeless",
"position": [
-1648,
-32
],
"parameters": {
"q": "={{ $json.Keywords }}"
},
"credentials": {
"scrapelessApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "967a693a-ef41-4c52-a7ea-c11f0466b171",
"name": "Split Out the url and text",
"type": "n8n-nodes-base.splitOut",
"position": [
-1264,
-576
],
"parameters": {
"options": {},
"fieldToSplitOut": "extractedLinks"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "4c84fe22-5af1-4ca5-b07d-737dbb01c073",
"connections": {
"Markdown": {
"main": [
[
{
"node": "HTML",
"type": "main",
"index": 0
}
]
]
},
"Aggregate": {
"main": [
[
{
"node": "Convert to File",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields1": {
"main": [
[
{
"node": "Analyze target keywords on Google SERP",
"type": "main",
"index": 0
}
]
]
},
"Convert to File": {
"main": [
[
{
"node": "Pinecone Vector Store",
"type": "main",
"index": 0
}
]
]
},
"Crawl all Blogs": {
"main": [
[
{
"node": "Parse content and extract information",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
],
[
{
"node": "Scrape detailed contents",
"type": "main",
"index": 0
}
]
]
},
"Basic LLM Chain1": {
"main": [
[
{
"node": "Markdown",
"type": "main",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "Pinecone Vector Store",
"type": "ai_document",
"index": 0
}
]
]
},
"Window Buffer Memory": {
"ai_memory": [
[
{
"node": "AI Agent1",
"type": "ai_memory",
"index": 0
}
]
]
},
"Pinecone Vector Store3": {
"main": [
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Embeddings Google Gemini": {
"ai_embedding": [
[
{
"node": "Pinecone Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Scrape detailed contents": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Embeddings Google Gemini3": {
"ai_embedding": [
[
{
"node": "Pinecone Vector Store3",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Google Gemini Chat Model1": {
"ai_languageModel": [
[
{
"node": "Basic LLM Chain1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Google Gemini Chat Model3": {
"ai_languageModel": [
[
{
"node": "AI Agent1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Split Out the url and text": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "Pinecone Vector Store3",
"type": "main",
"index": 0
}
]
]
},
"Recursive Character Text Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"When clicking \u2018Execute workflow\u2019": {
"main": [
[
{
"node": "Crawl all Blogs",
"type": "main",
"index": 0
},
{
"node": "Edit Fields1",
"type": "main",
"index": 0
}
]
]
},
"Parse content and extract information": {
"main": [
[
{
"node": "Split Out the url and text",
"type": "main",
"index": 0
}
]
]
},
"Analyze target keywords on Google SERP": {
"main": [
[
{
"node": "Basic LLM Chain1",
"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.
googlePalmApipineconeApiscrapelessApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
Source: https://n8n.io/workflows/6057/ — 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.
This simple philosophy changes the way we think about automated sales agents. Context changes everything. In this 4-part workflow, we start by creating a knowledge base that will act as context across
Code Extractfromfile. Uses manualTrigger, sort, httpRequest, compression. Event-driven trigger; 50 nodes.
BambooHR AI-Powered Company Policies and Benefits Chatbot. Uses manualTrigger, documentDefaultDataLoader, embeddingsOpenAi, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 50 nodes.
BambooHR AI-Powered Company Policies and Benefits Chatbot. Uses manualTrigger, documentDefaultDataLoader, embeddingsOpenAi, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 50 nodes.
2464. Uses httpRequest, compression, editImage, documentDefaultDataLoader. Event-driven trigger; 50 nodes.