This workflow corresponds to n8n.io template #10689 — we link there as the canonical source.
This workflow follows the Chainllm → Google Sheets 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": "Zx5WoAbZTSf18n4J",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "SEO Watchlist",
"tags": [],
"nodes": [
{
"id": "82daf0e8-8e16-4cbc-8e3b-e7479f34410c",
"name": "Decodo",
"type": "@decodo/n8n-nodes-decodo.decodo",
"position": [
-240,
-272
],
"parameters": {
"url": "={{ $json.url }}"
},
"credentials": {
"decodoApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "59b88a5c-c118-4b38-9d5b-718715a04f22",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1008,
-256
],
"parameters": {
"rule": {
"interval": [
{
"daysInterval": 5
}
]
}
},
"typeVersion": 1.2
},
{
"id": "123b1816-aebd-445c-8d59-6da6237a7afc",
"name": "Get row(s) in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-688,
-256
],
"parameters": {
"sheetName": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "url",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "c276ad3c-11af-478a-855e-f24c92ca8d23",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-464,
-256
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "54d54e11-3d6d-46b1-a7ac-b2956fb3a5ae",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-96,
-112
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "bf125187-f623-4135-86e3-47b1e4f16d56",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
128,
-112
],
"parameters": {
"autoFix": true,
"jsonSchemaExample": "{\n \"url\": \"string\",\n \"fetched_at\": \"ISO8601\",\n \"status\": 200,\n \"final_url\": \"string\",\n \"summary\": {\n \"page_type\": \"string\",\n \"language\": \"string\",\n \"primary_keyword\": \"string|null\",\n \"overall_score\": 0.0\n },\n \"checks\": [\n {\n \"id\": \"title\",\n \"status\": \"pass|warn|fail\",\n \"score\": 0.0, \n \"details\": \"short string\",\n \"evidence\": [\"title tag value\", \"...\"],\n \"confidence\": 0.0 \n }\n ],\n \"issues\": [\n {\n \"id\": \"missing_meta_description\",\n \"severity\": \"critical|high|medium|low\",\n \"message\": \"short string\",\n \"location\": \"head|body|headers|http\",\n \"examples\": [\"example fix snippet or replacement string\"],\n \"priority\": 1,\n \"estimated_impact\": \"high|medium|low\",\n \"confidence\": 0.0\n }\n ],\n \"recommendations\": [\n {\n \"id\": \"fix_title\",\n \"severity\": \"high\",\n \"instruction\": \"copyable instruction or code snippet\",\n \"priority\": 1,\n \"estimated_time_minutes\": 15,\n \"confidence\": 0.85\n }\n ],\n \"metrics\": {\n \"content_word_count\": 0,\n \"h1_count\": 0,\n \"image_count\": 0,\n \"images_missing_alt\": 0,\n \"internal_links\": 0,\n \"external_links\": 0,\n \"word_density\": [{\"term\":\"x\",\"count\":0,\"density\":0.0}],\n \"lighthouse\": {\"performance\":0,\"accessibility\":0,\"seo\":0,\"best_practices\":0}\n }\n}"
},
"typeVersion": 1.3
},
{
"id": "d953e10d-8803-41ab-8030-9c1930d5b5c4",
"name": "SEO Analyzer",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
0,
-272
],
"parameters": {
"text": "=Input\n{{ JSON.stringify($json.results[0] )}}\n",
"batching": {},
"messages": {
"messageValues": [
{
"message": "=# Role\n* act as an SEO expert\n\n# Instructions\n- Analyze the page, Return JSON based on schema, No explanation or extra text \u2014 only JSON\n- This is very important tasks, analyze carefully\n\n# CHECKS TO ANALYZE:\n* Metadata quality and duplication\n* Content length vs top 3 competitors (approx)\n* H1/H2 structure and keyword signaling\n* Schema.org types and common error\n* Page speed & CWV flags (LCP>2.5s, CLS>0.1, INP>200ms)\n* Mobile friendly\n* Images alt presence and size\n* Internal linking count and broken link detection (only flag if obvious)\n* Canonical alignment (canonical should point to final_url)\n* Noindex or X-Robots headers\n\n# SCORING:\nUse weights: \n* metadata 15\n* content 25\n* perf 20\n* index 15\n* links 10\n* schema 5\n* Provide `overall_score` 0..100."
}
]
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "19ee3c62-4603-434a-8a7a-10dea5c2d6ff",
"name": "Google Gemini Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
160,
80
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "25a50839-c9c1-4313-b8e0-0e06763f907c",
"name": "Notify Team",
"type": "n8n-nodes-base.telegram",
"position": [
-128,
-672
],
"parameters": {
"text": "=\u26a0\ufe0fINFORMATION\u26a0\ufe0f\n\nDate: {{ new Date() }}\nKindly check the gsheets for the latest analysis result\n",
"chatId": "=",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "7a300660-f15b-4b09-9ec1-97b74233a6f1",
"name": "Store Result",
"type": "n8n-nodes-base.googleSheets",
"position": [
784,
-160
],
"parameters": {
"columns": {
"value": {
"url": "={{ $json.url }}",
"date": "={{ $json.time }}",
"checks": "={{ $json.checks }}",
"issues": "={{ $json.issues }}",
"recommendations": "={{ $json.recommendations }}"
},
"schema": [
{
"id": "date",
"type": "string",
"display": true,
"required": false,
"displayName": "date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "url",
"type": "string",
"display": true,
"required": false,
"displayName": "url",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "checks",
"type": "string",
"display": true,
"required": false,
"displayName": "checks",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "issues",
"type": "string",
"display": true,
"required": false,
"displayName": "issues",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "recommendations",
"type": "string",
"display": true,
"required": false,
"displayName": "recommendations",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 955620984,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1uvnAqq36EoJqdTN01oHCsQs7eqP0zVP3BM_ZJ7avepQ/edit#gid=955620984",
"cachedResultName": "seo watchlist result"
},
"documentId": {
"__rl": true,
"mode": "url",
"value": ""
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "d6f00305-d35e-4cbe-aa42-af4968b44334",
"name": "Mapping Result",
"type": "n8n-nodes-base.code",
"position": [
448,
-272
],
"parameters": {
"jsCode": "const checks = $input.first().json.output.checks.map((el) => {\n return `${el.id} - Status: ${el.status} - Score: ${el.score} - ${el.details}`\n})\n\nconst issues = $input.first().json.output.issues.map((el) => {\n return `${el.id} - Severity: ${el.severity} - Priority: ${el.priority} - ${el.location}`\n})\n\nconst recommendations = $input.first().json.output.recommendations.map((el) => {\n return `${el.id} - Severity: ${el.severity} - Priority: ${el.priority} - ${el.instruction}`\n})\n\nreturn {\n time: $input.first().json.output.fetched_at,\n url: $input.first().json.output.final_url,\n checks: checks.join(\"\\n\\n\"),\n issues: issues.join(\"\\n\\n\"),\n recommendations: recommendations.join(\"\\n\\n\")\n}"
},
"typeVersion": 2
},
{
"id": "13be0f47-4c4e-4436-8b6b-43613215ad1f",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-640,
64
],
"parameters": {
"width": 720,
"height": 480,
"content": "## \u2705 Loop Over Items\n\nTakes each URL one-by-one and processes them separately. This keeps the workflow stable and organized.\n\n## \u2705 Decodo\n\nFetches live data from the website (title, content, tags, speed signals, etc.) so it can be analyzed.\n\n## \u2705 SEO Analyzer\n\nUses AI to review the website and create an SEO report based on scoring rules (content, metadata, links, speed, etc.).\n\n## \u2705 Structured Output Parser\n\nMakes sure the AI\u2019s answer comes back as clean, valid JSON. This prevents messy or unexpected text."
},
"typeVersion": 1
},
{
"id": "a0aa3d15-d6fe-46b5-b0bd-4f0b49fbcd96",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-176,
-912
],
"parameters": {
"width": 208,
"height": 400,
"content": "## Notify Team (Telegram)\n\nSends a Telegram message telling the team the analysis is complete and results are in the sheet."
},
"typeVersion": 1
},
{
"id": "612dfbd1-1d55-4d9c-a233-69373f9b3629",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
736,
-400
],
"parameters": {
"width": 208,
"height": 400,
"content": "## Store Result (Google Sheets)\n\nAdds a new row to the results sheet with the report for that URL, so results are saved historically."
},
"typeVersion": 1
},
{
"id": "064068f6-1fcc-41ce-9d12-36cf31d2ce0c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1472,
-1040
],
"parameters": {
"color": 2,
"width": 944,
"height": 960,
"content": "# Automated SEO Watchlist: Continuous Audits Powered by Decodo\n\n## \u2705 What this workflow does\nIt automatically audits website pages for SEO issues, stores results in Google Sheets, and notifies the team \u2014 completely hands-free.\n\n## \u2705 How it works\n- The workflow starts every 5 days on its own.\n- It reads a list of page URLs from Google Sheets.\n- Each page is processed one at a time for reliability.\n- Decodo \u2014 the main tech of this system \u2014 collects real content, tags, headings, speed signals, and more from each page.\n- AI analyzes the data using SEO best practices and creates a structured score/report.\n- Results are turned into short, human-friendly summaries.\n- A new entry is added to Google Sheets for tracking over time.\n- A Telegram message alerts the team when fresh results are ready.\n\n## \u2705 Why Decodo matters\nDecodo powers the entire audit \u2014 it pulls real, live page data so the AI can accurately judge SEO health.\nWithout Decodo, there\u2019s nothing to analyze.\n\n## \u2705 What you get\n- Automatic SEO auditing\n- Clear next steps and recommendations\n- Historical results stored as a log\n- No manual checking or reporting\n\n## \u2705 Great for\nMarketing teams, agencies, product sites, blogs, or anyone who wants continuous SEO monitoring with zero effort."
},
"typeVersion": 1
},
{
"id": "f4989071-9c52-4f63-9397-8277eb29de2a",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
592,
-256
],
"parameters": {
"width": 208,
"height": 400,
"content": "## Mapping Result (Code)\n\nTurns the JSON report into short, readable summaries (checks, issues, recommendations) and prepares them for Sheets."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "1e3a9a25-0d7f-45e7-9822-66decde09df0",
"connections": {
"Decodo": {
"main": [
[
{
"node": "SEO Analyzer",
"type": "main",
"index": 0
}
]
]
},
"SEO Analyzer": {
"main": [
[
{
"node": "Mapping Result",
"type": "main",
"index": 0
}
]
]
},
"Store Result": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Mapping Result": {
"main": [
[
{
"node": "Store Result",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[
{
"node": "Notify Team",
"type": "main",
"index": 0
}
],
[
{
"node": "Decodo",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get row(s) in sheet",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "SEO Analyzer",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "SEO Analyzer",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Google Gemini Chat Model1": {
"ai_languageModel": [
[
{
"node": "Structured Output Parser",
"type": "ai_languageModel",
"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.
decodoApigooglePalmApigoogleSheetsOAuth2ApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automate continuous SEO audits with Decodo and Gemini AI — live data, smart insights, and Google Sheets tracking with team alerts.
Source: https://n8n.io/workflows/10689/ — 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.
Effortlessly generate, review, and publish SEO-optimized blog posts to WordPress using AI and automation.
Sign up for Decodo — get better pricing here
Sign up for Decodo HERE for Discount
Sign up for Decodo HERE for Discount
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.