AutomationFlowsSlack & Telegram › Monitor Competitor SEO Changes with Customjs Scraper, Sheets & Slack Alerts

Monitor Competitor SEO Changes with Customjs Scraper, Sheets & Slack Alerts

ByCustomJS @customjs on n8n.io

This n8n workflow demonstrates how to monitor competitor websites for SEO changes by scraping content and updating a Google Sheet. It uses the Scraper node from customjs.space to extract HTML content and parse key SEO elements like , , , and meta description. Reads a list of…

Cron / scheduled trigger★★★★☆ complexity7 nodesGoogle SheetsSlack@Custom Js/N8N Nodes Pdf Toolkit V2
Slack & Telegram Trigger: Cron / scheduled Nodes: 7 Complexity: ★★★★☆ Added:

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

This workflow follows the Google Sheets → Slack 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
{
  "id": "xYHWzOasirB8h66T",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Monitor competitor SEO changes with CustomJS Scraper, Sheets & Slack alerts",
  "tags": [
    "customjs",
    "scraper",
    "seo",
    "competitor-analysis",
    "google-sheets",
    "automation",
    "monitoring",
    "slack",
    "content-tracking",
    "web-scraping",
    "alerting",
    "n8n-community-nodes"
  ],
  "nodes": [
    {
      "id": "ef41b994-e38a-46ab-9a2b-532e3d82e44b",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "8a854cea-bb9c-447b-b3d8-91fd94edf8a9",
      "name": "Get row(s) in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        240,
        0
      ],
      "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": "1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o/edit?usp=drivesdk",
          "cachedResultName": "Competitor SEO Monitor"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1e0d59b1-0561-4a29-9bd4-16e5e9a1b5ae",
      "name": "Update row in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        496,
        240
      ],
      "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": "1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1sXsJitpuE8LFMKk_1VEL6n9tTKMcPWxgip_gSEG-x-o/edit?usp=drivesdk",
          "cachedResultName": "Competitor SEO Monitor"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "8a512c88-90dc-49bb-aa95-3fa29963b27c",
      "name": "Code \u2013 Extract SEO Elements",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        240
      ],
      "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": "a73139cb-709b-4457-8c31-c88c17c6318d",
      "name": "If \u2013 Check for SEO Changes",
      "type": "n8n-nodes-base.if",
      "position": [
        720,
        240
      ],
      "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": "31ac6d74-0837-407f-9ffe-537fc1d4b51a",
      "name": "Slack Notification \u2013 Alert on Changes",
      "type": "n8n-nodes-base.slack",
      "position": [
        976,
        224
      ],
      "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 }} \u2192 {{ $('Update row in sheet').item.json.Title }} \\n- Meta Description: {{ $('Get row(s) in sheet').item.json['Meta Description'] }} \u2192 {{ $('Update row in sheet').item.json['Meta Description'] }} \\n- H1s:  {{ $('Get row(s) in sheet').item.json.H1s }} \u2192 {{ $('Update row in sheet').item.json.H1s }} \\n- H2s: {{ $('Get row(s) in sheet').item.json.H2s }} \u2192 {{ $('Update row in sheet').item.json.H2s }} \\nDate: {{ $('Update row in sheet').item.json.Date }}",
        "user": {
          "__rl": true,
          "mode": "list",
          "value": "U05EAUS4JCD",
          "cachedResultName": "hammadawan0007"
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "6a588e49-0b7f-4146-a3f0-b757ae3d3cfa",
      "name": "Scrape Website",
      "type": "@custom-js/n8n-nodes-pdf-toolkit-v2.pdfToolkit",
      "position": [
        48,
        240
      ],
      "parameters": {
        "url": "={{ $json.Websites }}",
        "resource": "web"
      },
      "credentials": {
        "customJsApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "09c629be-76e7-4f5a-a224-1111a55a56c1",
  "connections": {
    "Scrape Website": {
      "main": [
        [
          {
            "node": "Code \u2013 Extract SEO Elements",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Scrape Website",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update row in sheet": {
      "main": [
        [
          {
            "node": "If \u2013 Check for SEO Changes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If \u2013 Check for SEO Changes": {
      "main": [
        [
          {
            "node": "Slack Notification \u2013 Alert on Changes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2013 Extract SEO Elements": {
      "main": [
        [
          {
            "node": "Update row in sheet",
            "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.

Pro

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

About this workflow

This n8n workflow demonstrates how to monitor competitor websites for SEO changes by scraping content and updating a Google Sheet. It uses the Scraper node from customjs.space to extract HTML content and parse key SEO elements like , , , and meta description. Reads a list of…

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

More Slack & Telegram workflows → · Browse all categories →

Related workflows

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

Slack & Telegram

This n8n workflow illustrates how to monitor and track SSL certificate expiration dates for any domain using the SSL Checker node from customJS. It automatically updates a Google Sheet with the number

Google Sheets, Slack, @Custom Js/N8N Nodes Pdf Toolkit V2
Slack & Telegram

This workflow continuously monitors the Meta Ads Library for new creatives from a specific competitor pages, logs them into Google Sheets, and sends a concise Telegram notification with the number of

HTTP Request, Telegram, Google Sheets +1
Slack & Telegram

Enhance financial oversight with this automated n8n workflow. Triggered every 5 minutes, it fetches real-time bank transactions via an API, enriches and transforms the data, and applies smart logic to

HTTP Request, Email Send, Google Sheets +1
Slack & Telegram

This workflow automates competitive price intelligence using Bright Data's enterprise web scraping API. On a scheduled basis (default: daily at 9 AM), the system loops through configured competitor pr

HTTP Request, Google Sheets, Slack +1
Slack & Telegram

Ensure your customer SLAs never slip with this n8n automation template. The workflow runs on a schedule, fetching open tickets from Zendesk, calculating SLA time remaining, and sending proactive alert

Zendesk, Slack, Google Sheets