{
  "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
          }
        ]
      ]
    }
  }
}