AutomationFlowsAI & RAG › Monitor Website Changes with Bright Data, Claude, Airtable and Slack

Monitor Website Changes with Bright Data, Claude, Airtable and Slack

ByToolMonsters @toolmonsters on n8n.io

A schedule trigger periodically fetches the list of URLs to monitor from your CRM (Airtable by default) Bright Data Web Unlocker scrapes each page (handles JS, CAPTCHAs, geo-blocks) Claude Sonnet 4.6 compares the new HTML against the previous snapshot and ignores noise…

Cron / scheduled trigger★★★★☆ complexityAI-powered14 nodesAirtable@Brightdata/N8N Nodes BrightdataAnthropicSlack
AI & RAG Trigger: Cron / scheduled Nodes: 14 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Airtable → 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": "YxAoRB4mMYOwQeXl",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "AI Website Change Monitor powered by Bright Data",
  "tags": [],
  "nodes": [
    {
      "id": "0dcad4a0-fef6-431a-9ba4-13373161862f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -816,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 540,
        "height": 768,
        "content": "# \ud83d\udc40 AI Website Change Monitor powered by Bright Data\n\nMonitor any list of URLs (competitor pricing, product pages, docs, regulations\u2026) and get notified the moment something visibly changes.\n\n## How it works\n\n1. **Schedule Trigger** runs the workflow on your interval\n2. **Airtable** returns the active URLs to monitor\n3. **Bright Data Web Unlocker** fetches each page (handles JS, CAPTCHAs, geo-blocks)\n4. **Claude Sonnet 4.6** compares the new HTML to the previous snapshot, ignoring noise (timestamps, build IDs, CSS\u2026)\n5. The new snapshot is saved back to your CRM\n6. If a real change is detected, **Slack** notifies your team\n\n## Why Bright Data?\n\n- Bypasses CAPTCHAs, bot detection and geo-blocks\n- Renders JS-heavy pages (SPAs, dynamic content)\n- Reliable for daily monitoring at scale\n\n## Prerequisites\n\n- A [Bright Data](https://brightdata.com) account with a Web Unlocker zone\n- An [Anthropic](https://anthropic.com) API key (any Claude model works)\n- A CRM/DB to store URLs and snapshots (Airtable shown by default)\n- A [Slack](https://slack.com) workspace and channel\n\n## Setup (~10 min)\n\n1. Connect Airtable, Bright Data, Anthropic and Slack credentials\n2. Set the Schedule Trigger interval (hourly, daily\u2026)\n3. Add URLs to your CRM with `Active = TRUE`\n4. Activate the workflow"
      },
      "typeVersion": 1
    },
    {
      "id": "e62e7037-e2a6-4630-9096-80ec8884d767",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -224,
        448
      ],
      "parameters": {
        "color": 4,
        "width": 760,
        "height": 496,
        "content": "## \ud83d\ude80 1. Trigger & Get URLs\n\nThe **Schedule Trigger** kicks off the run, **Airtable** returns the active URLs, and the **loop** processes them one by one (so a single failure won't kill the run).\n\n### \ud83d\udd04 Swap-friendly\n- Trigger \u2192 Webhook, Cron, Form, Chat\n- CRM \u2192 HubSpot, Notion, Sheets, Postgres, Supabase\u2026"
      },
      "typeVersion": 1
    },
    {
      "id": "8c4071ef-a920-42f0-88ee-e46a932e9874",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        752
      ],
      "parameters": {
        "color": 3,
        "width": 476,
        "height": 480,
        "content": "## \ud83c\udf10 2. Scrape with Bright Data\n\n**Bright Data Web Unlocker** fetches each page as clean HTML, then **Truncate HTML** keeps the first 90,000 chars to fit the LLM context window.\n\n- Handles JS, CAPTCHAs, geo-blocks\n- Adjust the truncation limit per model"
      },
      "typeVersion": 1
    },
    {
      "id": "921edfb9-4579-480f-80ed-7970256ca108",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        960
      ],
      "parameters": {
        "color": 5,
        "width": 360,
        "height": 320,
        "content": "## \ud83e\udde0 3. AI Diff Analysis\n\n**Claude Sonnet 4.6** compares the new HTML against the previous snapshot. Returns:\n- `FIRST_RUN` if no previous version\n- `NO_CHANGE` if only noise changed\n- A 2-3 sentence summary otherwise\n\n\ud83d\udd04 Swap for any LLM (GPT-5, Gemini, Mistral\u2026)"
      },
      "typeVersion": 1
    },
    {
      "id": "20d1c3e2-b303-4a82-995a-e9eed06d8285",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1376,
        1264
      ],
      "parameters": {
        "color": 6,
        "width": 608,
        "height": 460,
        "content": "## \ud83d\udcbe 4. Save & Notify\n\n1. **Save Snapshot** stores the new HTML + AI summary back to your CRM\n2. **Change Detected?** filters out `NO_CHANGE` and `FIRST_RUN`\n3. **Notify Slack** posts an alert only when something real happened\n\n### \ud83d\udd04 Swap Slack for anything\nEmail, Discord, Teams, Telegram, SMS, Notion, Google Docs, a CRM task, a webhook\u2026"
      },
      "typeVersion": 1
    },
    {
      "id": "5754edee-2f98-45b9-bbf9-34bc8010bac1",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -144,
        624
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "89dff558-f14e-4ef3-90a1-caf1c5c49b12",
      "name": "Get URLs to Monitor",
      "type": "n8n-nodes-base.airtable",
      "position": [
        48,
        736
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultUrl": "",
          "cachedResultName": "Web Monitor"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_TABLE_ID",
          "cachedResultUrl": "",
          "cachedResultName": "URLs"
        },
        "options": {},
        "operation": "search",
        "filterByFormula": "{Active} = TRUE()"
      },
      "typeVersion": 2.2
    },
    {
      "id": "aa8c6b1c-4424-42ff-9ea2-371d27117cfd",
      "name": "Loop Over URLs",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        272,
        832
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "99a10fa0-d2ed-48c9-a117-85f08411d0bf",
      "name": "Scrape Page with Bright Data",
      "type": "@brightdata/n8n-nodes-brightdata.brightData",
      "position": [
        512,
        944
      ],
      "parameters": {
        "url": "={{ $json.fields.URL }}",
        "zone": {
          "__rl": true,
          "mode": "list",
          "value": "n8n_unlocker",
          "cachedResultName": "n8n_unlocker"
        },
        "country": {
          "__rl": true,
          "mode": "list",
          "value": "us"
        },
        "requestOptions": {}
      },
      "typeVersion": 1
    },
    {
      "id": "9a2e0561-c1c3-4879-860c-64c856bba9cd",
      "name": "Truncate HTML",
      "type": "n8n-nodes-base.code",
      "position": [
        720,
        1104
      ],
      "parameters": {
        "jsCode": "const fullHtml = String($input.item.json);\n\nreturn {\n  json: {\n    body: fullHtml.substring(0, 90000)\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "c9bae1dd-1557-4f1d-be80-d52e8d046c2e",
      "name": "AI Diff Analyzer",
      "type": "@n8n/n8n-nodes-langchain.anthropic",
      "position": [
        912,
        1232
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "claude-sonnet-4-6"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "content": "=Compare two versions of a webpage and detect if anything visibly changed.\n\nPage: {{ $('Get URLs to Monitor').item.json.fields.Label }}\nURL: {{ $('Get URLs to Monitor').item.json.fields.URL }}\n\nPREVIOUS VERSION:\n{{ $('Get URLs to Monitor').item.json.fields['Last HTML'] }}\n\nCURRENT VERSION:\n{{ $json.body }}\n\nInstructions:\n- If PREVIOUS VERSION is empty, respond exactly: FIRST_RUN\n- Compare both versions for VISIBLE content changes (pricing, features, copy, products)\n- Ignore: HTML tags, timestamps, build IDs, CSS, scripts, meta tags, dynamic IDs\n- If only structural/technical noise changed, respond exactly: NO_CHANGE\n- Otherwise, in 2-3 sentences describe what visibly changed\n\nOutput: plain text only, no preamble."
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b61b123c-a2c2-418b-8ce8-8fc878038862",
      "name": "Save Snapshot to CRM",
      "type": "n8n-nodes-base.airtable",
      "position": [
        1232,
        1328
      ],
      "parameters": {
        "base": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_BASE_ID",
          "cachedResultUrl": "",
          "cachedResultName": "Web Monitor"
        },
        "table": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_AIRTABLE_TABLE_ID",
          "cachedResultUrl": "",
          "cachedResultName": "URLs"
        },
        "columns": {
          "value": {
            "id": "={{ $('Get URLs to Monitor').item.json.id }}",
            "Last HTML": "={{ $('Truncate HTML').item.json.body }}",
            "Last Checked At": "={{ $now.toISO() }}",
            "Last Change Summary": "={{ $json.content[0].text }}"
          },
          "schema": [
            {
              "id": "id",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": true,
              "required": false,
              "displayName": "id",
              "defaultMatch": true
            },
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Label",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Label",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last HTML",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Last HTML",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Checked At",
              "type": "dateTime",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Last Checked At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Last Change Summary",
              "type": "string",
              "display": true,
              "removed": false,
              "readOnly": false,
              "required": false,
              "displayName": "Last Change Summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Active",
              "type": "boolean",
              "display": true,
              "removed": true,
              "readOnly": false,
              "required": false,
              "displayName": "Active",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update"
      },
      "typeVersion": 2.2
    },
    {
      "id": "cce179b9-e70c-4116-a3b1-7822fef4dd41",
      "name": "Change Detected?",
      "type": "n8n-nodes-base.if",
      "position": [
        1488,
        1456
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "fd5232fd-376c-4eb9-b9da-7c4e5f030395",
              "operator": {
                "type": "string",
                "operation": "notContains"
              },
              "leftValue": "={{ $json.fields['Last Change Summary'] }}",
              "rightValue": "NO_CHANGE"
            },
            {
              "id": "63748665-b174-4d08-a644-c713d4215412",
              "operator": {
                "type": "string",
                "operation": "notContains"
              },
              "leftValue": "={{ $json.fields['Last Change Summary'] }}",
              "rightValue": "FIRST_RUN"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "647c0dc3-c072-4ece-8e60-7e29f8fb1917",
      "name": "Notify Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1728,
        1568
      ],
      "parameters": {
        "text": "=\ud83d\udd14 Website change detected: {{ $json.fields.Label }}\n\n\ud83d\udd17 {{ $json.fields.URL }}\n\n\ud83d\udcdd What changed:\n{{ $json.fields['Last Change Summary'] }}\n\n\u23f0 Detected: {{ $now.toFormat('LLL d, HH:mm') }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SLACK_CHANNEL_ID",
          "cachedResultName": "monitoring"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "typeVersion": 2.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "3cb62f12-afce-436b-bcc9-5ed48d77628b",
  "connections": {
    "Notify Slack": {
      "main": [
        [
          {
            "node": "Loop Over URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Truncate HTML": {
      "main": [
        [
          {
            "node": "AI Diff Analyzer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over URLs": {
      "main": [
        [],
        [
          {
            "node": "Scrape Page with Bright Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Diff Analyzer": {
      "main": [
        [
          {
            "node": "Save Snapshot to CRM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Change Detected?": {
      "main": [
        [
          {
            "node": "Notify Slack",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Get URLs to Monitor",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get URLs to Monitor": {
      "main": [
        [
          {
            "node": "Loop Over URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Snapshot to CRM": {
      "main": [
        [
          {
            "node": "Change Detected?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Page with Bright Data": {
      "main": [
        [
          {
            "node": "Truncate HTML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

A schedule trigger periodically fetches the list of URLs to monitor from your CRM (Airtable by default) Bright Data Web Unlocker scrapes each page (handles JS, CAPTCHAs, geo-blocks) Claude Sonnet 4.6 compares the new HTML against the previous snapshot and ignores noise…

Source: https://n8n.io/workflows/15483/ — 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

Complaints arrive via Gmail or a web form webhook Claude AI classifies each complaint: fault category, priority (P1/P2/P3), tenant tone, and drafts an acknowledgement email The right technician is loo

Anthropic, Airtable, Gmail +2
AI & RAG

A daily Schedule Trigger pulls active LinkedIn job-search URLs from Airtable Bright Data Web Unlocker scrapes each search results page GPT extracts structured job data from the raw HTML A second GPT c

Airtable, @Brightdata/N8N Nodes Brightdata, OpenAI +2
AI & RAG

This workflow automatically fetches product reviews from your WooCommerce store, analyzes the sentiment of each review using AI, stores the results in Airtable and sends a summary of positive, neutral

HTTP Request, OpenAI, Airtable +1
AI & RAG

Automatically enriches every new LinkedIn lead added to your Airtable base with AI-structured data and notifies your team in Slack. Airtable Trigger polls for new leads every minute BrightData scrapes

@Brightdata/N8N Nodes Brightdata, OpenAI, Airtable +2
AI & RAG

A scheduled process aggregates content from eight distinct data sources and standardizes all inputs into a unified format. AI models perform sentiment scoring, detect conspiracy or misinformation sign

HTTP Request, OpenAI, Postgres +2