AutomationFlowsAI & RAG › Audit Competitor SEO Content with Decodo, Gemini, and Google Sheets

Audit Competitor SEO Content with Decodo, Gemini, and Google Sheets

ByAtta @attakhalighi on n8n.io

This advanced workflow automates the most time-consuming part of SEO: auditing competitor articles and identifying exactly where your brand can outshine them. It extracts deep content from top-ranking URLs, compares it against your specific brand identity, and generates a…

Event trigger★★★★☆ complexityAI-powered20 nodesGoogle Sheets@Decodo/N8N Nodes DecodoAgentGoogle Gemini ChatOutput Parser Structured
AI & RAG Trigger: Event Nodes: 20 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #13817 — we link there as the canonical source.

This workflow follows the Agent → 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 →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "951ffb80-2b9b-4992-b692-5fb14c75af51",
      "name": "Data Sourcing",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        320,
        0
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao/edit#gid=0",
          "cachedResultName": "Target Keywords"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao/edit?usp=drivesdk",
          "cachedResultName": "[Project Name] - Competitor Content Intelligence Engine"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "fc4228b7-0b33-4356-a873-e26ccfdd1ab4",
      "name": "Manual Execution",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -400,
        -112
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "486a26aa-d3d8-47bb-81b9-6be96e4ede87",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "position": [
        -96,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b9886785-eddf-46c0-a840-78130b349ed2",
              "name": "target_geo",
              "type": "string",
              "value": "United States"
            },
            {
              "id": "4a19c78e-e02d-4c48-8bc9-514bdce02c86",
              "name": "target_locale",
              "type": "string",
              "value": "en-US"
            },
            {
              "id": "2cd09b73-0c79-463e-8844-34f6156d4ddd",
              "name": "serp_results_amount",
              "type": "number",
              "value": 10
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "6c774d11-6e9b-4061-8c1a-38c0226391cf",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -400,
        96
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "3b8e9665-8e81-465f-a64f-fa02b44a7f5e",
      "name": "Universal Scraping",
      "type": "@decodo/n8n-nodes-decodo.decodo",
      "maxTries": 3,
      "position": [
        1120,
        0
      ],
      "parameters": {
        "geo": "={{ $('Config').item.json.target_geo }}",
        "url": "={{ $json.url }}"
      },
      "credentials": {
        "decodoApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1,
      "waitBetweenTries": 5000
    },
    {
      "id": "7dc09cda-7e0b-4e3e-bc54-8f3047b0c888",
      "name": "Google Search",
      "type": "@decodo/n8n-nodes-decodo.decodo",
      "maxTries": 2,
      "position": [
        608,
        0
      ],
      "parameters": {
        "geo": "={{ $('Config').item.json.target_geo }}",
        "query": "={{ $json[\"Target Keyword\"] }}",
        "locale": "={{ $('Config').item.json.target_locale }}",
        "headless": false,
        "operation": "google_search",
        "results_limit": "={{ $('Config').item.json.serp_results_amount }}"
      },
      "credentials": {
        "decodoApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1
    },
    {
      "id": "a40aae73-fb12-4591-9be8-c96885addb72",
      "name": "AI Content Auditor",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1648,
        0
      ],
      "parameters": {
        "text": "=Please perform a deep SEO audit on the following competitor content for the keyword: \"**{{ $('Split to Competitor URLs').item.json.keyword }}**\".\n\n**Competitor URL:** {{ $('Split to Competitor URLs').item.json.url }}\n**Current Rank:** {{ $('Split to Competitor URLs').item.json.rank }}\n\n---\n**PAGE CONTENT (MARKDOWN):**\n{{ $json.body }}\n---\n\nAnalyze the content and provide the Audit Requirements defined in your system instructions.\n\n\n",
        "options": {
          "systemMessage": "=You are a Senior SEO Content Strategist. Your mission is to perform a \"Search Intent Audit\" to find the delta between this competitor and our brand.\n\n### OUR BRAND IDENTITY (THE GOLD STANDARD):\n{{ $(\"Brand Info\").first().json['Brand Info'] }}\n\n### INPUT CONTEXT:\n- Target Keyword: {{ $('Split to Competitor URLs').item.json.keyword }}\n- SERP Rank: {{ $('Split to Competitor URLs').item.json.rank }}\n- Content Source: Competitor Markdown extraction.\n\n### STRATEGIC LOGIC RULES:\n1. THE GAP DEFINITION: A \"Content Gap\" is NOT just missing text. It is a specific angle, data point, or user-need that OUR BRAND provides (based on the Identity above) which is absent in the competitor's text.\n2. WINNING FACTOR: Identify if they are winning due to \"Topical Depth\" (long-form), \"Technical Authority\" (tools/data), or \"User Experience\" (skimmable headers).\n3. ACTION PLAN: This must be a \"Checkmate\" instruction. If they are broad, we must be specific. If they are technical, we must be accessible.\n\n### OUTPUT SCHEMA (STRICT JSON ONLY):\n{\n  \"primary_h1\": \"String\",\n  \"word_count\": Integer,\n  \"top_topics\": [\"Topic 1\", \"Topic 2\", \"Topic 3\"],\n  \"winning_factor\": \"Detailed 1-sentence analysis of their SEO moat.\",\n  \"content_gap\": \"What specific 'Brand Value' from our identity is missing here?\",\n  \"action_plan\": \"Specific instruction: 'Write a [Section Type] that focuses on [Brand USP] to outperform their [Competitor Section].'\"\n}\n\n### CONSTRAINTS:\n- No conversational filler. \n- If the Markdown is empty or invalid, return \"Error: No Content\".\n- Ensure the 'action_plan' uses the brand voice defined in the Brand Identity."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "retryOnFail": true,
      "typeVersion": 3.1,
      "waitBetweenTries": 2000
    },
    {
      "id": "20ca7b8f-d70d-43fc-b22d-c264997d46c2",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1744,
        368
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ecf99171-08a3-4892-b751-ff2d30d3b6ee",
      "name": "Split to Competitor URLs",
      "type": "n8n-nodes-base.code",
      "position": [
        832,
        0
      ],
      "parameters": {
        "jsCode": "// 1. Get configuration, keywords, and search results\nconst config = $(\"Config\").first().json;\nconst allKeywords = $(\"Data Sourcing\").all();\nconst allSearchResults = $(\"Google Search\").all();\n\n// Use the limit from Config, or default to 5 if not found\nconst resultLimit = config.serp_results_amount || 10; \n\nlet finalOutput = [];\n\n// 2. Loop through every search result set\nallSearchResults.forEach((searchResult, searchIndex) => {\n  \n  // Get the keyword from the matching index\n  const keyword = allKeywords[searchIndex].json[\"Target Keyword\"] || \"Keyword Not Found\";\n  \n  // Navigate the deep Decodo path\n  let organicResults = searchResult.json.results[0].content.results.results.organic;\n\n  // 3. LIMIT THE RESULTS HERE\n  // slice(0, X) takes only the first X items from the array\n  const limitedResults = organicResults.slice(0, resultLimit);\n\n  // 4. Map each URL (up to the limit) to its own n8n item\n  limitedResults.forEach(result => {\n    finalOutput.push({\n      json: {\n        keyword: keyword,\n        url: result.url,\n        title: result.title,\n        rank: result.pos\n      },\n      // Keeps the internal n8n breadcrumb trail alive\n      pairedItem: {\n        item: searchIndex\n      }\n    });\n  });\n});\n\nreturn finalOutput;"
      },
      "executeOnce": false,
      "typeVersion": 2
    },
    {
      "id": "d396db94-48b4-4090-a58b-be9c97bd6db3",
      "name": "Extract Body",
      "type": "n8n-nodes-base.html",
      "position": [
        1360,
        0
      ],
      "parameters": {
        "options": {},
        "operation": "extractHtmlContent",
        "dataPropertyName": "results[0].content",
        "extractionValues": {
          "values": [
            {
              "key": "body",
              "cssSelector": "body",
              "skipSelectors": "img, link"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "212c8736-425a-44d0-8c00-7eedbf0ca617",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1856,
        208
      ],
      "parameters": {
        "autoFix": true,
        "jsonSchemaExample": "{\n  \"primary_h1\": \"String\",\n  \"word_count\": 2000,\n  \"top_topics\": [\"Topic 1\", \"Topic 2\", \"Topic 3\"],\n  \"winning_factor\": \"Detailed 1-sentence analysis of their SEO moat.\",\n  \"content_gap\": \"What specific 'Brand Value' from our identity is missing here?\",\n  \"action_plan\": \"Specific instruction: 'Write a [Section Type] that focuses on [Brand USP] to outperform their [Competitor Section].'\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "163c6d64-c908-4fe1-a7d9-8ef5742e4686",
      "name": "Brand Info",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        112,
        0
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 489437890,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao/edit#gid=489437890",
          "cachedResultName": "Brand Identity"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao/edit?usp=drivesdk",
          "cachedResultName": "[Project Name] - Competitor Content Intelligence Engine"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "e8253dfd-c299-409b-a046-c24dab8718a1",
      "name": "Strategy Master Writer",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2304,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "Rank": "={{ $('Split to Competitor URLs').item.json.rank }}",
            "Keyword": "={{ $('Split to Competitor URLs').item.json.keyword }}",
            "The Gap": "={{ $json.output.content_gap }}",
            "Primary H1": "={{ $json.output.primary_h1 }}",
            "Action Plan": "={{ $json.output.action_plan }}",
            "Competitor URL": "={{ $('Split to Competitor URLs').item.json.url }}",
            "Winning Factor": "={{ $json.output.winning_factor }}"
          },
          "schema": [
            {
              "id": "Keyword",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Keyword",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Competitor URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Competitor URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Rank",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Rank",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Primary H1",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Primary H1",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Winning Factor",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Winning Factor",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "The Gap",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "The Gap",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Action Plan",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Action Plan",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 823247616,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao/edit#gid=823247616",
          "cachedResultName": "Competitor Audit Feed"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao/edit?usp=drivesdk",
          "cachedResultName": "[Project Name] - Competitor Content Intelligence Engine"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1e90967c-c146-4aa6-871a-458c9157581e",
      "name": "Done",
      "type": "n8n-nodes-base.noOp",
      "position": [
        2496,
        0
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "6b5984ef-d21c-49f6-939b-095e848e3eb7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -160,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 320,
        "content": "## Config"
      },
      "typeVersion": 1
    },
    {
      "id": "59655aba-c72a-400c-84c0-446d9ab3574c",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 320,
        "content": "## Market Discovery"
      },
      "typeVersion": 1
    },
    {
      "id": "831694d7-de6a-49ce-b44d-b4d1e4fb04b3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1056,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 464,
        "height": 320,
        "content": "## Intelligence Harvesting"
      },
      "typeVersion": 1
    },
    {
      "id": "4d87610f-5be4-4395-88ce-891d496132fd",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 640,
        "content": "## Strategic Audit"
      },
      "typeVersion": 1
    },
    {
      "id": "87562eb4-fdbe-4d61-b456-bfba2f3036a5",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2208,
        -96
      ],
      "parameters": {
        "color": 7,
        "width": 528,
        "height": 320,
        "content": "## Reporting Deck"
      },
      "typeVersion": 1
    },
    {
      "id": "36cf2345-1e5a-4156-974b-b8c087365f69",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1168,
        -464
      ],
      "parameters": {
        "width": 592,
        "height": 688,
        "content": "## **AI-Powered Competitor Content Intelligence Engine**\n\n### **Master Google Sheet:**\n[View Here](https://docs.google.com/spreadsheets/d/1FRRxOZeNt7rEi-87Nlm_wKSP4Ue2FnMSeIKBNm6Onao/edit?gid=0#gid=0)\n\n### **How It Works:**\n1. **Inputs**: Retrieves keywords and Brand USPs from the `Target Keywords` and `Brand Identity` tabs.\n2. **Discovery**: Uses Decodo to find and limit top competitors based on your `serp_results_amount` setting.\n3. **Extraction**: Scrapes clean Markdown content from each URL, bypassing bot-blockers for high-fidelity analysis.\n4. **Analysis**: Gemini 3 Flash identifies exactly what the competitor is missing based on your live brand identity.\n5. **Reporting**: Appends a structured \"Action Plan\" to the `Competitor Audit Feed` sheet.\n\n### **Setup & Global Configuration:**\n* **Credentials**: Ensure API keys are active for [Decodo](https://visit.decodo.com/c/6679292/3071239/17480), Google Sheets, and Gemini.\n* **Sheets Setup**: Maintain the URL above as the central source for all data nodes.\n* **Target Geo (`target_geo`)**: Set the search region (e.g., `United States`) in the **Config** node to match your local customer's perspective.\n* **Target Locale (`target_locale`)**: Refine search relevance by setting the language and region code (e.g., `en-US`).\n* **Search Depth (`serp_results_amount`)**: Control workflow speed and token costs by defining the maximum number of competitors to analyze per keyword (e.g., `5` or `10`)."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Config": {
      "main": [
        [
          {
            "node": "Brand Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Brand Info": {
      "main": [
        [
          {
            "node": "Data Sourcing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Body": {
      "main": [
        [
          {
            "node": "AI Content Auditor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Data Sourcing": {
      "main": [
        [
          {
            "node": "Google Search",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Search": {
      "main": [
        [
          {
            "node": "Split to Competitor URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Execution": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Content Auditor": {
      "main": [
        [
          {
            "node": "Strategy Master Writer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Universal Scraping": {
      "main": [
        [
          {
            "node": "Extract Body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Strategy Master Writer": {
      "main": [
        [
          {
            "node": "Done",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Content Auditor",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "Structured Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Split to Competitor URLs": {
      "main": [
        [
          {
            "node": "Universal Scraping",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Content Auditor",
            "type": "ai_outputParser",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This advanced workflow automates the most time-consuming part of SEO: auditing competitor articles and identifying exactly where your brand can outshine them. It extracts deep content from top-ranking URLs, compares it against your specific brand identity, and generates a…

Source: https://n8n.io/workflows/13817/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Never miss a competitor price change again.

@Decodo/N8N Nodes Decodo, Google Gemini Chat, Output Parser Structured +3
AI & RAG

Sign up for Decodo — get better pricing here

Form Trigger, Google Sheets, Output Parser Structured +4
AI & RAG

Sign up for Decodo HERE for Discount

@Decodo/N8N Nodes Decodo, Output Parser Structured, Google Gemini +4
AI & RAG

This workflow transforms your Telegram bot into an intelligent creative assistant. It can chat conversationally, fetch trending image prompts from PromptHero for inspiration, or perform a deep "remix"

Telegram Trigger, Output Parser Structured, Telegram +6
AI & RAG

This automation is designed to help you generate AI-powered music tracks, cover art, and fully rendered music videos — all triggered from a simple Telegram chat and managed via Google Sheets.

OpenAI Chat, Memory Buffer Window, Output Parser Structured +11