{
  "id": "HrDqOpwmDSw6DcID",
  "meta": {
    "instanceId": "584c88d9c6d3d6b187b85d8fb66968f47d2267f8a5ea40d3d59ea7a8bb53bd89"
  },
  "name": "Monitor Competitor SEO Changes with CustomJS Scraper, Google Sheets & Slack Alerts",
  "tags": [
    "customjs",
    "scraper",
    "seo",
    "competitor-analysis",
    "google-sheets",
    "automation",
    "monitoring",
    "slack",
    "content-tracking",
    "web-scraping",
    "alerting",
    "n8n-community-nodes"
  ],
  "nodes": [
    {
      "id": "be8eb1c8-f161-45a0-98df-9789f3c98630",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1472,
        -96
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "280e7b76-03a5-4ea1-b993-f7771e024849",
      "name": "Get row(s) in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1232,
        -96
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE-x-o",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o/edit?usp=drivesdk",
          "cachedResultName": "Competitor SEO Monitor"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "googleSheetsOAuth2Api Credential"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "3ce2a8ca-e37d-4e2f-bce4-f96503c7f661",
      "name": "Update row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -976,
        144
      ],
      "parameters": {
        "columns": {
          "value": {
            "H1s": "={{ $json.h1s }}",
            "H2s": "={{ $json.h2s }}",
            "Date": "={{new Date()}}",
            "Title": "={{ $json.title }}",
            "Websites": "={{ $('Get row(s) in sheet').item.json.Websites }}",
            "Meta Description": "={{ $json.metaDescription }}"
          },
          "schema": [
            {
              "id": "Websites",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Websites",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Meta Description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Meta Description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "H1s",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "H1s",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "H2s",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "H2s",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Websites"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE-x-o",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o/edit?usp=drivesdk",
          "cachedResultName": "Competitor SEO Monitor"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "googleSheetsOAuth2Api Credential"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "9749e365-4d77-411b-b353-d326f1cdd9f4",
      "name": "CustomJS Scraper – Fetch HTML",
      "type": "@custom-js/n8n-nodes-pdf-toolkit.scraper",
      "position": [
        -1440,
        144
      ],
      "parameters": {
        "url": "={{ $json.Websites }}",
        "commands": {
          "command": [
            {}
          ]
        },
        "returnValueType": "text"
      },
      "credentials": {
        "customJsApi": {
          "id": "credential-id",
          "name": "customJsApi Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5acf718b-5dc6-4452-9306-969d5aa9c365",
      "name": "Code – Extract SEO Elements",
      "type": "n8n-nodes-base.code",
      "position": [
        -1216,
        144
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const html = $json.output || \"\";\n\n// Extract <title>\nconst title = html.match(/<title[^>]*>([^<]*)<\\/title>/i)?.[1]?.trim() || null;\n\n// Extract meta description\nconst metaDescription = html.match(/<meta\\s+name=[\"']description[\"'][^>]*content=[\"']([^\"']+)[\"']/i)?.[1]?.trim() || null;\n\n// Extract all <h1> headings\nconst h1s = [...html.matchAll(/<h1[^>]*>(.*?)<\\/h1>/gi)].map(m => m[1].trim()).join(\" \");\nconst h2s = [...html.matchAll(/<h2[^>]*>(.*?)<\\/h2>/gi)].map(m => m[1].trim()).join(\" \");\n\nreturn   {\n    json: {\n      title,\n      metaDescription,\n      h1s,\n      h2s\n    }\n  }\n;"
      },
      "typeVersion": 2
    },
    {
      "id": "24353fa4-84b1-4f3b-85d3-5718e8faa50a",
      "name": "If – Check for SEO Changes",
      "type": "n8n-nodes-base.if",
      "position": [
        -752,
        144
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "fbf35a1d-0fd6-4b58-a9cb-df5e6ca2df1c",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $('Get row(s) in sheet').item.json.Title }}",
              "rightValue": "={{ $json.Title }}"
            },
            {
              "id": "dd23caf7-3257-4482-b3f6-57b70ac63a45",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $('Get row(s) in sheet').item.json[\"Meta Description\"] }}",
              "rightValue": "={{ $json[\"Meta Description\"] }}"
            },
            {
              "id": "2c0160ac-d790-4f8b-990f-848633030898",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $('Get row(s) in sheet').item.json.H1s }}",
              "rightValue": "={{ $json.H1s }}"
            },
            {
              "id": "f55ca75f-4d60-4fa6-acec-1159858e6604",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $('Get row(s) in sheet').item.json.H2s }}",
              "rightValue": "={{ $json.H2s }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "771bc30e-ebe1-4d50-8ed9-89b19b63366e",
      "name": "Slack Notification – Alert on Changes",
      "type": "n8n-nodes-base.slack",
      "position": [
        -496,
        128
      ],
      "webhookId": "0dd1fff8-40ed-48e4-9218-9d5f1499c6d1",
      "parameters": {
        "text": "=:warning: Competitor SEO Change Detected!\\nWebsite: {{ $('Update row in sheet').item.json.Websites }} \\n- Title: {{ $('Get row(s) in sheet').item.json.Title }} → {{ $('Update row in sheet').item.json.Title }} \\n- Meta Description: {{ $('Get row(s) in sheet').item.json['Meta Description'] }} → {{ $('Update row in sheet').item.json['Meta Description'] }} \\n- H1s:  {{ $('Get row(s) in sheet').item.json.H1s }} → {{ $('Update row in sheet').item.json.H1s }} \\n- H2s: {{ $('Get row(s) in sheet').item.json.H2s }} → {{ $('Update row in sheet').item.json.H2s }} \\nDate: {{ $('Update row in sheet').item.json.Date }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "SLACK_USER_ID",
          "cachedResultName": "SLACK_USER_ID"
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "id": "credential-id",
          "name": "slackApi Credential"
        }
      },
      "typeVersion": 2.3
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "04c0eafd-bcb2-4d78-9f23-538cb3745ef6",
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "CustomJS Scraper – Fetch HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update row in sheet": {
      "main": [
        [
          {
            "node": "If – Check for SEO Changes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If – Check for SEO Changes": {
      "main": [
        [
          {
            "node": "Slack Notification – Alert on Changes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code – Extract SEO Elements": {
      "main": [
        [
          {
            "node": "Update row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "CustomJS Scraper – Fetch HTML": {
      "main": [
        [
          {
            "node": "Code – Extract SEO Elements",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}