This workflow corresponds to n8n.io template #12809 — we link there as the canonical source.
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": "",
"meta": {
"templateCredsSetupCompleted": false
},
"name": "Find keyword opportunities with SE Ranking competitor analysis and AI leaderboard",
"tags": [],
"nodes": [
{
"id": "52205087-2642-4f64-9b96-eff1285202db",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
448,
-544
],
"parameters": {
"color": 5,
"width": 736,
"height": 888,
"content": "## Find competitor keyword opportunities with SE Ranking and AI search\n\n## Who is this for\n- SEO agencies tracking competitors\n- Content teams finding gaps\n- Marketing teams planning strategy\n\n## What you'll get\n- Top 5 competitors auto-discovered\n- Keyword gaps from each competitor\n- Lost keywords (quick wins)\n- Topic expansion ideas\n- AI visibility across ChatGPT, Perplexity, Gemini, AI Overview\n- Everything exported to Google Sheets\n\n## How it works\n1. Discovers your top 5 organic competitors\n2. Pulls keyword gaps for each competitor\n3. Finds keywords you recently lost\n4. Expands topics with related keywords\n5. Checks your AI search visibility\n6. Scores everything by opportunity\n7. Exports to Google Sheets\n\n## Setup steps\n1. Install SE Ranking node v1.3.5+\n2. Add your SE Ranking API credentials\n3. Open Configuration node and set:\n - Your domain\n - Your brand name\n - Target country (us, uk, etc.)\n - Min volume and max difficulty\n4. Connect Google Sheets (optional)\n\n## Customization\nChange min_volume and max_difficulty in Configuration to get more or fewer opportunities."
},
"typeVersion": 1
},
{
"id": "ed215442-6cde-46e1-be77-48a1a8d4c9da",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
672,
800
],
"parameters": {},
"typeVersion": 1
},
{
"id": "293c1790-aafa-43fb-b5db-624f2050e9df",
"name": "Configuration",
"type": "n8n-nodes-base.set",
"position": [
848,
800
],
"parameters": {
"mode": "raw",
"options": {},
"jsonOutput": "{\n \"your_domain\": \"seranking.com\",\n \"your_brand\": \"SE Ranking\",\n \"source\": \"us\",\n \"currency\": \"USD\",\n \"competitor_count\": 5,\n \"min_volume\": 100,\n \"max_difficulty\": 60,\n \"known_competitors\": [\n {\"domain\": \"semrush.com\", \"brand\": \"Semrush\"},\n {\"domain\": \"ahrefs.com\", \"brand\": \"Ahrefs\"},\n {\"domain\": \"moz.com\", \"brand\": \"Moz\"}\n ],\n \"ai_engines\": [\"chatgpt\", \"perplexity\", \"gemini\", \"ai-overview\"]\n}"
},
"typeVersion": 3.4
},
{
"id": "781b85da-ff6e-47cd-886e-23a7a5c651af",
"name": "Get your domain overview",
"type": "@seranking/n8n-nodes-seranking.seRanking",
"position": [
2496,
-160
],
"parameters": {
"domain": "={{ $('Configuration').item.json.your_domain }}",
"additionalFields": {}
},
"credentials": {
"seRankingApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "2cc8ddc1-80de-430a-90b5-e5984cfa3849",
"name": "Auto-discover top competitors",
"type": "@seranking/n8n-nodes-seranking.seRanking",
"position": [
1072,
496
],
"parameters": {
"domain": "={{ $('Configuration').item.json.your_domain }}",
"source": "={{ $('Configuration').item.json.source }}",
"operation": "getCompetitors",
"additionalFields": {}
},
"credentials": {
"seRankingApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "f594a47f-db0e-4cdb-b97b-ea89d8a78f28",
"name": "Extract competitor domains",
"type": "n8n-nodes-base.code",
"position": [
1264,
496
],
"parameters": {
"jsCode": "const competitors = $input.all();\nconst config = $('Configuration').first().json;\n\nconst results = competitors\n .slice(0, config.competitor_count)\n .map((item, index) => ({\n json: {\n rank: index + 1,\n competitor_domain: item.json.domain,\n common_keywords: item.json.common_keywords || item.json.common || 0,\n your_domain: config.your_domain,\n source: config.source\n }\n }));\n\nreturn results.length > 0 ? results : [{\n json: {\n rank: 1,\n competitor_domain: 'semrush.com',\n common_keywords: 0,\n your_domain: config.your_domain,\n source: config.source\n }\n}];"
},
"typeVersion": 2
},
{
"id": "5ce8cd73-ee9b-446d-b8e0-4c6b3275b4be",
"name": "Wait before gap analysis",
"type": "n8n-nodes-base.wait",
"position": [
1472,
496
],
"parameters": {
"amount": 2
},
"typeVersion": 1.1
},
{
"id": "cdab3d2b-f9e2-4474-9028-71ec1f86fae1",
"name": "Get keyword gaps",
"type": "@seranking/n8n-nodes-seranking.seRanking",
"position": [
1664,
496
],
"parameters": {
"domain": "={{ $json.your_domain }}",
"operation": "getKeywordsComparison",
"compareDomain": "={{ $json.competitor_domain }}",
"additionalFields": {}
},
"credentials": {
"seRankingApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "3d5fedd4-5631-412f-ad50-b2a6a13a86fc",
"name": "Filter & score keyword gaps",
"type": "n8n-nodes-base.code",
"position": [
1824,
496
],
"parameters": {
"jsCode": "const config = $('Configuration').first().json;\nconst allGaps = $input.all();\nconst currentCompetitor = $('Extract competitor domains').item.json;\n\nconst filtered = allGaps\n .filter(item => {\n const k = item.json;\n return k.volume >= config.min_volume && \n k.difficulty <= config.max_difficulty;\n })\n .map(item => {\n const k = item.json;\n \n const volumeScore = k.volume * 0.4;\n const difficultyScore = (100 - k.difficulty) * 0.3;\n const trafficScore = (k.traffic || 0) * 0.3;\n const opportunityScore = Math.round(volumeScore + difficultyScore + trafficScore);\n \n return {\n json: {\n source: $('Wait before gap analysis').first().json.source,\n type: 'KEYWORD_GAP',\n competitor_domain: currentCompetitor.competitor_domain,\n keyword: k.keyword,\n volume: k.volume,\n difficulty: k.difficulty,\n cpc: k.cpc || 0,\n competition: k.competition || 0,\n competitor_position: k.position,\n estimated_traffic: k.traffic || Math.round(k.volume * 0.15),\n opportunity_score: opportunityScore,\n priority: opportunityScore > 5000 ? 'HIGH' : opportunityScore > 2000 ? 'MEDIUM' : 'LOW'\n }\n };\n });\n\nreturn filtered;"
},
"typeVersion": 2
},
{
"id": "0f7365ce-43b7-45db-9027-ead456063ba9",
"name": "Wait before lost keywords",
"type": "n8n-nodes-base.wait",
"position": [
2272,
704
],
"parameters": {
"amount": 2
},
"typeVersion": 1.1
},
{
"id": "d9de553b-2927-46d3-8306-5af0a1e761a6",
"name": "Get your lost keywords",
"type": "@seranking/n8n-nodes-seranking.seRanking",
"position": [
2464,
704
],
"parameters": {
"domain": "={{ $('Configuration').item.json.your_domain }}",
"source": "={{ $('Configuration').item.json.source }}",
"operation": "getKeywords",
"additionalFields": {
"limit": 50,
"orderType": "desc",
"posChange": "lost",
"orderField": "volume",
"volumeFrom": "={{ $('Configuration').item.json.min_volume }}"
}
},
"credentials": {
"seRankingApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "56b1775c-08f6-4ba0-9a1c-035f644fa509",
"name": "Format lost keywords",
"type": "n8n-nodes-base.code",
"position": [
2672,
704
],
"parameters": {
"jsCode": "const lostKeywords = $input.all();\n\nconst opportunities = lostKeywords\n .slice(0, 30)\n .map(item => {\n const k = item.json;\n const opportunityScore = Math.round((k.volume * 0.6) + ((100 - (k.difficulty || 50)) * 0.4));\n \n return {\n json: {\n type: 'LOST_KEYWORD',\n keyword: k.keyword,\n volume: k.volume,\n difficulty: k.difficulty || 50,\n cpc: k.cpc || 0,\n previous_position: k.prev_position || 'N/A',\n estimated_traffic_lost: Math.round(k.volume * 0.15),\n opportunity_score: opportunityScore,\n priority: 'HIGH',\n action: (k.difficulty || 50) < 40 ? 'QUICK WIN: Re-optimize' : 'Recover: Update content'\n }\n };\n });\n\nreturn opportunities;"
},
"typeVersion": 2
},
{
"id": "f1864efd-5d86-43d7-9fb7-8685856eed3f",
"name": "Loop through keywords",
"type": "n8n-nodes-base.splitInBatches",
"position": [
2224,
496
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "b73d4d7a-7fe3-4dcb-92b7-9325d3edbac0",
"name": "Get similar keywords",
"type": "@seranking/n8n-nodes-seranking.seRanking",
"position": [
2448,
320
],
"parameters": {
"source": "={{ $json.source }}",
"keyword": "={{ $json.keyword }}",
"resource": "keywordResearch",
"operation": "getSimilar",
"additionalFields": {
"limit": 10
}
},
"credentials": {
"seRankingApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "12e43616-9a1f-4c32-9455-879f52316d2d",
"name": "Get related keywords",
"type": "@seranking/n8n-nodes-seranking.seRanking",
"position": [
2448,
480
],
"parameters": {
"source": "={{ $json.source }}",
"keyword": "={{ $json.keyword }}",
"resource": "keywordResearch",
"operation": "getRelated",
"additionalFields": {
"limit": 10
}
},
"credentials": {
"seRankingApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "02f714a9-3bb9-41b2-9c41-1f002ff0d0b2",
"name": "Merge similar & related",
"type": "n8n-nodes-base.merge",
"position": [
2656,
400
],
"parameters": {
"mode": "combine",
"options": {},
"combinationMode": "mergeByPosition"
},
"typeVersion": 2.1
},
{
"id": "ba980e54-88e6-4a75-adcc-37f0b54fef75",
"name": "Format topic expansion",
"type": "n8n-nodes-base.code",
"position": [
2432,
176
],
"parameters": {
"jsCode": "const similar = $('Get similar keywords').all();\nconst related = $('Get related keywords').all();\nconst config = $('Configuration').first().json;\n\n// Extract keywords from nested structure\nlet allKeywords = [];\n\n// Process similar keywords\nsimilar.forEach(item => {\n if (item.json.keywords && Array.isArray(item.json.keywords)) {\n allKeywords = allKeywords.concat(item.json.keywords);\n }\n});\n\n// Process related keywords\nrelated.forEach(item => {\n if (item.json.keywords && Array.isArray(item.json.keywords)) {\n allKeywords = allKeywords.concat(item.json.keywords);\n }\n});\n\nif (allKeywords.length === 0) {\n return [{\n json: {\n type: 'TOPIC_EXPANSION',\n keyword: 'NO_EXPANSION_DATA',\n volume: 0,\n difficulty: 0,\n cpc: 0,\n estimated_traffic: 0,\n opportunity_score: 0,\n priority: 'LOW',\n action: 'No expansion keywords found'\n }\n }];\n}\n\nconst formatted = allKeywords\n .filter(k => k.volume >= config.min_volume)\n .map(k => {\n const opportunityScore = Math.round((k.volume * 0.5) + ((100 - (k.difficulty || 50)) * 0.5));\n \n return {\n json: {\n type: 'TOPIC_EXPANSION',\n keyword: k.keyword,\n volume: k.volume,\n difficulty: k.difficulty || 50,\n cpc: k.cpc || 0,\n estimated_traffic: Math.round(k.volume * 0.12),\n opportunity_score: opportunityScore,\n priority: opportunityScore > 3000 ? 'MEDIUM' : 'LOW',\n action: 'Expand: Add to content cluster'\n }\n };\n });\n\nreturn formatted.length > 0 ? formatted : [{\n json: {\n type: 'TOPIC_EXPANSION',\n keyword: 'NO_KEYWORDS_PASSED_FILTERS',\n volume: 0,\n difficulty: 0,\n cpc: 0,\n estimated_traffic: 0,\n opportunity_score: 0,\n priority: 'LOW',\n action: 'No keywords passed volume filter'\n }\n}];"
},
"typeVersion": 2,
"alwaysOutputData": false
},
{
"id": "cfd0e620-d3aa-4456-9ad5-776ce39cd41c",
"name": "Wait before AI leaderboard",
"type": "n8n-nodes-base.wait",
"position": [
2352,
1152
],
"parameters": {
"amount": 2
},
"typeVersion": 1.1
},
{
"id": "c9ca72e7-c6d5-4854-b5dc-0784f93b018c",
"name": "Extract your AI visibility",
"type": "n8n-nodes-base.code",
"position": [
2752,
1152
],
"parameters": {
"jsCode": "const leaderboard = $input.first().json;\nconst config = $('Configuration').first().json;\n\n// Extract YOUR domain's results from the actual API structure\nconst yourResults = leaderboard.results?.[config.your_domain] || {};\n\nconst aiMetrics = {\n your_domain: config.your_domain,\n your_brand: config.your_brand,\n chatgpt_presence: yourResults.chatgpt?.link_presence || 0,\n chatgpt_brand_presence: yourResults.chatgpt?.brand_presence || 0,\n perplexity_presence: yourResults.perplexity?.link_presence || 0,\n perplexity_brand_presence: yourResults.perplexity?.brand_presence || 0,\n gemini_presence: yourResults.gemini?.link_presence || 0,\n gemini_brand_presence: yourResults.gemini?.brand_presence || 0,\n ai_overview_presence: yourResults['ai-overview']?.link_presence || 0,\n ai_overview_brand_presence: yourResults['ai-overview']?.brand_presence || 0\n};\n\nreturn [{ json: aiMetrics }];"
},
"typeVersion": 2
},
{
"id": "115eedd5-6dee-474b-884c-03c242d698a7",
"name": "Final scoring with AI context",
"type": "n8n-nodes-base.code",
"position": [
3632,
528
],
"parameters": {
"jsCode": "const allData = $input.all();\n\n// Separate by actual data structure\nconst domainData = allData.filter(item => item.json.organic && item.json._domain);\nconst aiData = allData.filter(item => item.json.chatgpt_presence !== undefined);\nconst opportunities = allData.filter(item => item.json.keyword && item.json.type);\n\nif (!domainData.length) throw new Error('No domain data - check connection');\nif (!aiData.length) throw new Error('No AI data - check connection');\n\nconst config = $('Configuration').first().json;\nconst yourDomain = domainData[0].json;\nconst aiMetrics = aiData[0].json;\n\n// Use actual structure: organic[0].keywords_count, traffic_sum, price_sum\nconst yourMetrics = {\n total_keywords: yourDomain.organic?.[0]?.keywords_count || 0,\n organic_traffic: yourDomain.organic?.[0]?.traffic_sum || 0,\n traffic_value: yourDomain.organic?.[0]?.price_sum || 0\n};\n\nconst sorted = opportunities\n .map(item => item.json)\n .sort((a, b) => b.opportunity_score - a.opportunity_score);\n\nreturn sorted.map((opp, index) => ({\n json: {\n rank: index + 1,\n analysis_date: new Date().toISOString().split('T')[0],\n your_domain: config.your_domain,\n your_brand: config.your_brand,\n your_total_keywords: yourMetrics.total_keywords,\n your_organic_traffic: yourMetrics.organic_traffic,\n your_traffic_value: yourMetrics.traffic_value,\n your_chatgpt_presence: aiMetrics.chatgpt_presence,\n your_chatgpt_brand_presence: aiMetrics.chatgpt_brand_presence,\n your_perplexity_presence: aiMetrics.perplexity_presence,\n your_perplexity_brand_presence: aiMetrics.perplexity_brand_presence,\n your_gemini_presence: aiMetrics.gemini_presence,\n your_gemini_brand_presence: aiMetrics.gemini_brand_presence,\n your_ai_overview_presence: aiMetrics.ai_overview_presence,\n your_ai_overview_brand_presence: aiMetrics.ai_overview_brand_presence,\n ...opp\n }\n}));"
},
"typeVersion": 2
},
{
"id": "5caa3fd6-e142-45b2-9829-e762b4a2c5e0",
"name": "Export to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
3824,
528
],
"parameters": {
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "id",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "",
"cachedResultUrl": "",
"cachedResultName": ""
}
},
"typeVersion": 4.7
},
{
"id": "ed2158f4-48bf-4e87-9c67-47a20e194fc3",
"name": "Extract top gap keywords",
"type": "n8n-nodes-base.code",
"position": [
2032,
496
],
"parameters": {
"jsCode": "// Extract top 10 keywords and output as individual items (one per keyword)\nconst allGaps = $('Filter & score keyword gaps').all();\n\nif (allGaps.length === 0) {\n // No keywords found, return empty to skip topic expansion\n return [];\n}\n\n// Get top 10 keywords sorted by opportunity score\nconst topKeywords = allGaps\n .sort((a, b) => b.json.opportunity_score - a.json.opportunity_score)\n .slice(0, 10);\n\n// Output each keyword as a separate item for the loop\nreturn topKeywords.map(item => ({\n json: {\n source: $input.first().json.source,\n keyword: item.json.keyword\n }\n}));"
},
"typeVersion": 2
},
{
"id": "725bd029-7f9d-4095-8ef1-cad4a4ab5477",
"name": "Get AI search leaderboard",
"type": "@seranking/n8n-nodes-seranking.seRanking",
"position": [
2528,
1184
],
"parameters": {
"source": "={{ $('Configuration').item.json.source }}",
"engines": [
"chatgpt",
"ai-overview",
"perplexity",
"gemini"
],
"resource": "aiSearch",
"operation": "getLeaderboard",
"competitors": {
"competitorValues": [
{
"brand": "={{ $('Configuration').item.json.known_competitors[2].brand }}",
"target": "={{ $('Configuration').item.json.known_competitors[2].domain }}"
}
]
},
"primaryBrand": "={{ $('Configuration').item.json.your_brand }}",
"primaryTarget": "={{ $('Configuration').item.json.your_domain }}"
},
"credentials": {
"seRankingApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "63fcc165-ce63-4865-9e96-576069e5cfb3",
"name": "Merge domain & topics",
"type": "n8n-nodes-base.merge",
"position": [
3200,
256
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "92d9346f-2f47-482b-9f87-79d8a4b55744",
"name": "Merge lost & AI",
"type": "n8n-nodes-base.merge",
"position": [
3216,
512
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "f57c1e94-d777-4e7e-ab27-db2de6aae88d",
"name": "Merge all data",
"type": "n8n-nodes-base.merge",
"position": [
3424,
400
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "f99e2104-cfd3-4c1d-8fb4-eeafb2dcb6a4",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
2176,
-304
],
"parameters": {
"color": 7,
"width": 384,
"height": 112,
"content": "### Domain Overview\nGet your baseline metrics (keywords, traffic, value)"
},
"typeVersion": 1
},
{
"id": "bbee334b-fcd4-4c82-94fe-d3edf84d8acd",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1488,
304
],
"parameters": {
"color": 7,
"width": 608,
"height": 144,
"content": "### Competitor Discovery & Gap Analysis\nAuto-discover top 5 competitors, analyze keyword gaps, expand topics with related keywords"
},
"typeVersion": 1
},
{
"id": "ebe576ee-8b92-4134-9666-bf9d0dfc8762",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2272,
864
],
"parameters": {
"color": 7,
"width": 448,
"height": 112,
"content": "### Lost Keywords\nFind quick wins from keywords you recently lost rankings for"
},
"typeVersion": 1
},
{
"id": "2aee4a65-7275-414b-9a6e-db96e0768a05",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2384,
1376
],
"parameters": {
"color": 7,
"width": 464,
"height": 112,
"content": "### AI Search Visibility\nTrack presence across ChatGPT, Perplexity, Gemini, AI Overview"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "",
"connections": {
"Configuration": {
"main": [
[
{
"node": "Get your domain overview",
"type": "main",
"index": 0
},
{
"node": "Auto-discover top competitors",
"type": "main",
"index": 0
},
{
"node": "Wait before lost keywords",
"type": "main",
"index": 0
},
{
"node": "Wait before AI leaderboard",
"type": "main",
"index": 0
}
]
]
},
"Merge all data": {
"main": [
[
{
"node": "Final scoring with AI context",
"type": "main",
"index": 0
}
]
]
},
"Merge lost & AI": {
"main": [
[
{
"node": "Merge all data",
"type": "main",
"index": 1
}
]
]
},
"Get keyword gaps": {
"main": [
[
{
"node": "Filter & score keyword gaps",
"type": "main",
"index": 0
}
]
]
},
"Format lost keywords": {
"main": [
[
{
"node": "Merge lost & AI",
"type": "main",
"index": 0
}
]
]
},
"Get related keywords": {
"main": [
[
{
"node": "Merge similar & related",
"type": "main",
"index": 1
}
]
]
},
"Get similar keywords": {
"main": [
[
{
"node": "Merge similar & related",
"type": "main",
"index": 0
}
]
]
},
"Loop through keywords": {
"main": [
[
{
"node": "Format topic expansion",
"type": "main",
"index": 0
}
],
[
{
"node": "Get similar keywords",
"type": "main",
"index": 0
},
{
"node": "Get related keywords",
"type": "main",
"index": 0
}
]
]
},
"Merge domain & topics": {
"main": [
[
{
"node": "Merge all data",
"type": "main",
"index": 0
}
]
]
},
"Format topic expansion": {
"main": [
[
{
"node": "Merge domain & topics",
"type": "main",
"index": 1
}
]
]
},
"Get your lost keywords": {
"main": [
[
{
"node": "Format lost keywords",
"type": "main",
"index": 0
}
]
]
},
"Merge similar & related": {
"main": [
[
{
"node": "Loop through keywords",
"type": "main",
"index": 0
}
]
]
},
"Extract top gap keywords": {
"main": [
[
{
"node": "Loop through keywords",
"type": "main",
"index": 0
}
]
]
},
"Get your domain overview": {
"main": [
[
{
"node": "Merge domain & topics",
"type": "main",
"index": 0
}
]
]
},
"Wait before gap analysis": {
"main": [
[
{
"node": "Get keyword gaps",
"type": "main",
"index": 0
}
]
]
},
"Get AI search leaderboard": {
"main": [
[
{
"node": "Extract your AI visibility",
"type": "main",
"index": 0
}
]
]
},
"Wait before lost keywords": {
"main": [
[
{
"node": "Get your lost keywords",
"type": "main",
"index": 0
}
]
]
},
"Extract competitor domains": {
"main": [
[
{
"node": "Wait before gap analysis",
"type": "main",
"index": 0
}
]
]
},
"Extract your AI visibility": {
"main": [
[
{
"node": "Merge lost & AI",
"type": "main",
"index": 1
}
]
]
},
"Wait before AI leaderboard": {
"main": [
[
{
"node": "Get AI search leaderboard",
"type": "main",
"index": 0
}
]
]
},
"Filter & score keyword gaps": {
"main": [
[
{
"node": "Extract top gap keywords",
"type": "main",
"index": 0
}
]
]
},
"Auto-discover top competitors": {
"main": [
[
{
"node": "Extract competitor domains",
"type": "main",
"index": 0
}
]
]
},
"Final scoring with AI context": {
"main": [
[
{
"node": "Export to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Configuration",
"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.
seRankingApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
SEO agencies doing competitor analysis for clients Content teams planning content strategies Marketing teams tracking competitive performance SEO professionals measuring AI search visibility
Source: https://n8n.io/workflows/12809/ — 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 template automates the enrichment of business leads from a Google Sheet by: Triggering when a row is activated Searching for company information with Serper.dev Generating and validating potentia
The automation starts by retreiving the unused queries from a sheet, executes queries in the web using Serper API and extracts linkedin profiles of decision makers.
Stop losing warm leads in the noise. This automation analyzes your lead engagement data, calculates priority scores based on activity and last contact date, and automatically queues your top 10 leads
This workflow helps you automatically collect verified business leads from Google Search using SerpAPI — no coding required. It extracts company names, websites, emails, and phone numbers directly fro
This workflow automates comprehensive SEO reporting by: Extracting keyword rankings and page performance from Google Search Console. Gathering organic reach metrics from Google Analytics. Analyzing in