AutomationFlowsWeb Scraping › Track Website Changes with Firecrawl, Gpt-5-mini, Notion, and Gmail

Track Website Changes with Firecrawl, Gpt-5-mini, Notion, and Gmail

ByScoutNow @scoutnow on n8n.io

Manually checking websites for updates or competitor changes can be tedious. This workflow automates the process by scraping target pages, capturing screenshots, and analyzing content changes using Firecrawl and GPT-5-mini. All updates are saved in Notion, and you can optionally…

Cron / scheduled trigger★★★★☆ complexityAI-powered26 nodes@Mendable/N8N Nodes FirecrawlNotionOpenAIHTTP RequestGmail
Web Scraping Trigger: Cron / scheduled Nodes: 26 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Gmail → HTTP Request 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": "JLVGKBUyHrR4YvLt",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Track Website Changes with Firecrawl, GPT-5-Mini, Notion, and Gmail",
  "tags": [],
  "nodes": [
    {
      "id": "5f7ea6a1-9f73-48bf-8369-86ecb58d3725",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "57c3bbff-226a-430d-b69c-00e4044afc1d",
      "name": "Define Target URLs",
      "type": "n8n-nodes-base.set",
      "position": [
        416,
        0
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "{\n  \"target_urls\": [\n  \"https://randomtextgenerator.com\",\n    \"https://randomuser.me/\"\n  ]\n}\n"
      },
      "typeVersion": 3.4
    },
    {
      "id": "4c669ef1-1705-4f20-8b4c-b98294c81a00",
      "name": "Define What Matters To You",
      "type": "n8n-nodes-base.set",
      "position": [
        1136,
        0
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "157b9aeb-158a-40a6-afc7-01ec48c95e1d",
              "name": "change_criteria",
              "type": "string",
              "value": "Either a visible text change or an image source update should be considered a change"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "c8d3280b-0d6c-41c2-936b-b8643f9dfc3c",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        800,
        0
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "target_urls"
      },
      "typeVersion": 1
    },
    {
      "id": "8fb04f75-c67b-4c9e-af3f-337d36efb4ff",
      "name": "Construct Notion Blocks",
      "type": "n8n-nodes-base.code",
      "position": [
        2912,
        0
      ],
      "parameters": {
        "jsCode": "const databasePages = $input.all();\nconst scrapedResults = $('Scrape Target URLs').all();\n\nif (databasePages.length !== scrapedResults.length) {\n  throw new Error('Database pages count does not match scraped results');\n}\n\nlet blocks = [];\n\nfor (let i = 0; i < databasePages.length; i++) {\n  const pageId = databasePages[i].json.id;\n  const scrapedContent = scrapedResults[i].json.data.markdown || '';\n\n  // Split into chunks of max 1500 chars\n  const chunkSize = 1500;\n  const chunks = [];\n\n  for (let start = 0; start < scrapedContent.length; start += chunkSize) {\n    chunks.push(scrapedContent.slice(start, start + chunkSize));\n  }\n\n  // Build objects for next node (Append block)\n  for (const chunk of chunks) {\n    blocks.push({\n      pageId,\n      chunk\n    });\n  }\n}\n\nreturn [\n  {\n    json: {\n      blocks\n    },\n    pairedItem: 0\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "4f0e3a4f-2e83-42ec-990a-633a7c1f89a5",
      "name": "Capture Screenshots",
      "type": "@mendable/n8n-nodes-firecrawl.firecrawl",
      "position": [
        2048,
        0
      ],
      "parameters": {
        "url": "={{ $('Split Out').item.json.target_urls }}",
        "operation": "scrape",
        "scrapeOptions": {
          "options": {
            "formats": {
              "format": [
                {
                  "type": "screenshot",
                  "fullPage": true
                }
              ]
            },
            "headers": {},
            "waitFor": 5000,
            "onlyMainContent": false
          }
        },
        "requestOptions": {}
      },
      "credentials": {
        "firecrawlApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "5862c23d-ed50-4509-ade9-e409b12ec85a",
      "name": "Scrape Target URLs",
      "type": "@mendable/n8n-nodes-firecrawl.firecrawl",
      "position": [
        1584,
        0
      ],
      "parameters": {
        "url": "={{ $('Split Out').item.json.target_urls }}",
        "operation": "scrape",
        "scrapeOptions": {
          "options": {
            "formats": {
              "format": [
                {}
              ]
            },
            "headers": {},
            "waitFor": 5000,
            "onlyMainContent": false
          }
        },
        "requestOptions": {}
      },
      "credentials": {
        "firecrawlApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e89f8a93-d675-4dc1-91c6-1bce387a55a5",
      "name": "Save Snapshots",
      "type": "n8n-nodes-base.notion",
      "position": [
        2480,
        0
      ],
      "parameters": {
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "2b0c5676-4824-80a1-a5d6-f33afd1fc387",
          "cachedResultUrl": "https://www.notion.so/2b0c5676482480a1a5d6f33afd1fc387",
          "cachedResultName": "Snapshots"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Name|title",
              "title": "={{ new Date().toISOString().split('T')[0] + '_' + $('Split Out').item.json.target_urls.replace(/^https?:\\/\\//, '') }}"
            },
            {
              "key": "Screenshot|files",
              "fileUrls": {
                "fileUrl": [
                  {
                    "url": "={{ $json.data.screenshot }}",
                    "name": "Screenshot"
                  }
                ]
              }
            },
            {
              "key": "URL|url",
              "urlValue": "={{ $('Split Out').item.json.target_urls }}"
            },
            {
              "key": "Created Date|date",
              "date": "={{ new Date().toISOString().split('T')[0] }}",
              "includeTime": false
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7ff3404a-e06a-40f4-8988-79f02a8724ac",
      "name": "Split Out Blocks",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        3392,
        0
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "blocks"
      },
      "typeVersion": 1
    },
    {
      "id": "a2e53381-7163-4d76-a7bf-4a077848d88a",
      "name": "Append Blocks",
      "type": "n8n-nodes-base.notion",
      "position": [
        3760,
        0
      ],
      "parameters": {
        "blockId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.pageId }}"
        },
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $json.chunk }}"
            }
          ]
        },
        "resource": "block"
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a6af5ebf-f064-4c4c-9dac-7bb7bb82a59f",
      "name": "Get Last Snapshots",
      "type": "n8n-nodes-base.notion",
      "position": [
        2400,
        688
      ],
      "parameters": {
        "limit": 1,
        "filters": {
          "conditions": [
            {
              "key": "URL|url",
              "urlValue": "={{ $('Split Out').item.json.target_urls }}",
              "condition": "equals"
            },
            {
              "key": "Created Date|date",
              "date": "={{ new Date(Date.now() - 86400000).toISOString().split('T')[0] }}",
              "condition": "on_or_before"
            }
          ]
        },
        "options": {
          "sort": {
            "sortValue": [
              {
                "key": "Created Date|date",
                "direction": "descending"
              }
            ]
          }
        },
        "resource": "databasePage",
        "matchType": "allFilters",
        "operation": "getAll",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "2b0c5676-4824-80a1-a5d6-f33afd1fc387",
          "cachedResultUrl": "https://www.notion.so/2b0c5676482480a1a5d6f33afd1fc387",
          "cachedResultName": "Snapshots"
        },
        "filterType": "manual"
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "919bd24e-9d01-4373-98e6-edaeda07993c",
      "name": "Combine Website Data",
      "type": "n8n-nodes-base.code",
      "position": [
        3056,
        688
      ],
      "parameters": {
        "jsCode": "const targetURLs = $('Split Out').all();\nconst currentScrapedResults = $('Scrape Target URLs').all();\nconst currentScreenshots = $('Capture Screenshots').all();\n\nconst lastSnapshots = $('Get Last Snapshots').all();\n\nconst fetchedBlocks = $input.all();\n\nlet websites = [];\n\nfor (let targetURL of targetURLs) {\n  targetURL = targetURL.json.target_urls;\n  \n  const lastSnapshot = lastSnapshots.find((item) => item.json.property_url.startsWith(targetURL))?.json;\n  \n  if(!lastSnapshot) continue;\n\n  const lastSnapshotDate = lastSnapshot.property_created_date.start;\n  \n  const lastScreenshot = lastSnapshot.property_screenshot[0];\n\n  const currentScrapedResult = currentScrapedResults.find((item) => item.json.data.metadata.url.startsWith(targetURL));\n\n  const currentScreenshot = currentScreenshots.find((item) => item.json.data.metadata.url.startsWith(targetURL)).json.data.screenshot;\n\n const currentDate = new Date().toISOString().split('T')[0];\n\n  const currentContent = currentScrapedResult.json.data.markdown;\n\n  const blocks = fetchedBlocks.filter((item) => item.json.parent_id == lastSnapshot.id);\n\n  const lastContent = blocks.map((block) => block.json.content).join('');\n\n  websites.push({\n    url: targetURL,\n    currentDate,\n    currentContent,\n    currentScreenshot,\n    lastSnapshotDate,\n    lastContent,\n    lastScreenshot,\n  })\n  \n}\n\nreturn [\n  {\n    json: {\n      websites\n    },\n    pairedItem: 0\n  }\n]"
      },
      "typeVersion": 2
    },
    {
      "id": "58fa418b-c04e-45c0-b3ee-cf18f793fdba",
      "name": "Split Out Data",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        3408,
        688
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "websites"
      },
      "typeVersion": 1
    },
    {
      "id": "b72256c3-9212-4760-8f08-e440f16b8eb1",
      "name": "Split Out Updates",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        4624,
        688
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "updates"
      },
      "typeVersion": 1
    },
    {
      "id": "4e8bf48a-e430-4c7f-b717-58968f26187d",
      "name": "Get Many Blocks",
      "type": "n8n-nodes-base.notion",
      "position": [
        2720,
        688
      ],
      "parameters": {
        "blockId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "resource": "block",
        "operation": "getAll",
        "returnAll": true
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9754ac3d-c8ad-47a0-b0a0-fc1741778e46",
      "name": "Compare Snapshots",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        3728,
        688
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini",
          "cachedResultName": "GPT-5-MINI"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "content": "=Compare the current website content with the last snapshot using the change criteria provided.  \nIf any meaningful change is detected, generate a concise change summary.  \nIf no meaningful change is detected, return exactly: NO_CHANGE.\n\nURL: {{ $json.url }}\n\nCurrent Date: {{ $json.currentDate }}\nLast Snapshot Date: {{ $json.lastSnapshotDate }}\n\nChange Criteria:\n{{ $('Define What Matters To You').item.json.change_criteria }}\n\nCurrent Content:\n\"\"\"\n{{ $json.currentContent }}\n\"\"\"\n\nPrevious Content:\n\"\"\"\n{{ $json.lastContent }}\n\"\"\""
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "b61f9c71-ab16-486b-8e53-080dc1bcf26b",
      "name": "Combine Snapshots and AI Analysis",
      "type": "n8n-nodes-base.code",
      "position": [
        4256,
        688
      ],
      "parameters": {
        "jsCode": "const aiAnalyses = $input.all();\nconst websites = $('Split Out Data').all();\n\nif(aiAnalyses.length != websites.length) {\n  throw new Error(`Mismatch in data length: ${aiAnalyses.length} AI analyses but ${websites.length} websites`);\n}\n\nlet updates = [];\n\nfor (let i = 0; i < websites.length; i++) {\n\n  const summary = aiAnalyses[i].json.output[0].content[0].text;\n  \n  if (summary.includes(\"NO_CHANGE\")) continue;\n\n  updates.push({\n    ...websites[i].json,\n    summary\n  });\n}\n\nreturn [\n  {\n    json: {\n      updates\n    },\n    pairedItem: 0\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "141b7c73-2424-4466-829c-694cbb4a835b",
      "name": "Create Updates",
      "type": "n8n-nodes-base.notion",
      "position": [
        5072,
        688
      ],
      "parameters": {
        "options": {},
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "2b0c5676-4824-80a0-83c6-f80d70c9b0ba",
          "cachedResultUrl": "https://www.notion.so/2b0c5676482480a083c6f80d70c9b0ba",
          "cachedResultName": "Updates"
        },
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Name|title",
              "title": "={{ new Date().toISOString().split('T')[0] + '_' + $json.url.replace(/^https?:\\/\\//, '') }}"
            },
            {
              "key": "Created At|date",
              "date": "={{ new Date().toISOString().split('T')[0] }}",
              "includeTime": false
            },
            {
              "key": "URL|url",
              "urlValue": "={{ $json.url }}"
            }
          ]
        }
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "1079db6f-727c-4477-9ac4-f731bc55bb11",
      "name": "Construct Update Pages",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5552,
        688
      ],
      "parameters": {
        "url": "=https://api.notion.com/v1/blocks/{{ $json.id }}/children",
        "method": "PATCH",
        "options": {},
        "jsonBody": "={\n  \"children\": [\n    {\n      \"object\": \"block\",\n      \"type\": \"column_list\",\n      \"column_list\": {\n        \"children\": [\n          {\n            \"object\": \"block\",\n            \"type\": \"column\",\n            \"column\": {\n              \"children\": [\n                {\n                  \"object\": \"block\",\n                  \"type\": \"heading_3\",\n                  \"heading_3\": {\n                    \"rich_text\": [\n                      {\n                        \"type\": \"text\",\n                        \"text\": {\n                          \"content\": \"Now ({{ $('Split Out Updates').item.json.currentDate }})\"\n                        }\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"object\": \"block\",\n                  \"type\": \"image\",\n                  \"image\": {\n                    \"type\": \"external\",\n                    \"external\": {\n                      \"url\": \"{{ $('Split Out Updates').item.json.currentScreenshot }}\"\n                    }\n                  }\n                }\n              ]\n            }\n          },\n          {\n            \"object\": \"block\",\n            \"type\": \"column\",\n            \"column\": {\n              \"children\": [\n                {\n                  \"object\": \"block\",\n                  \"type\": \"heading_3\",\n                  \"heading_3\": {\n                    \"rich_text\": [\n                      {\n                        \"type\": \"text\",\n                        \"text\": {\n                          \"content\": \"Previous ({{ $('Split Out Updates').item.json.lastSnapshotDate }})\"\n                        }\n                      }\n                    ]\n                  }\n                },\n                {\n                  \"object\": \"block\",\n                  \"type\": \"image\",\n                  \"image\": {\n                    \"type\": \"external\",\n                    \"external\": {\n                      \"url\": \"{{ $('Split Out Updates').item.json.lastScreenshot }}\"\n                    }\n                  }\n                }\n              ]\n            }\n          }\n        ]\n      }\n    },\n    {\n      \"object\": \"block\",\n      \"type\": \"heading_3\",\n      \"heading_3\": {\n        \"rich_text\": [{ \"type\": \"text\", \"text\": { \"content\": \"Summary\" } }]\n      }\n    },\n    {\n      \"object\": \"block\",\n      \"type\": \"paragraph\",\n      \"paragraph\": {\n        \"rich_text\": [\n          {\n            \"type\": \"text\",\n            \"text\": {\n              \"content\": \"{{ JSON.stringify($('Split Out Updates').item.json.summary).slice(1, -1) }}\"\n            }\n          }\n        ]\n      }\n    }\n  ]\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "notionApi"
      },
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "648b40d8-2aa4-4c04-abc0-e36de4f60efe",
      "name": "Send Email Updates",
      "type": "n8n-nodes-base.gmail",
      "position": [
        5136,
        0
      ],
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>Website Update Alert</title>\n</head>\n<body style=\"margin:0; padding:0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background-color:#f4f4f4;\">\n  <table align=\"center\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"margin:20px 0;\">\n    <tr>\n      <td align=\"center\">\n        <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" style=\"background-color:#ffffff; border-radius:10px; overflow:hidden; box-shadow:0 4px 12px rgba(0,0,0,0.1); padding:20px;\">\n          <tr>\n            <td align=\"center\">\n              <h2 style=\"color:#333333; margin:0 0 10px 0;\">Website Update Detected</h2>\n              <p style=\"color:#1a73e8; font-size:16px; margin:0 0 20px 0; line-height:1.4;\">{{ $json.url }}</p>\n            </td>\n          </tr>\n          <tr>\n            <td>\n              <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"margin:20px 0;\">\n                <tr>\n                  <td align=\"center\" width=\"50%\" style=\"padding-right:5px;\">\n                    <p style=\"text-align:center; font-weight:bold; margin:0 0 5px 0;\">Current</p>\n                    <p style=\"text-align:center; font-size:12px; color:#888888; margin:0 0 10px 0;\">{{ $json.currentDate }}</p>\n                    <img src=\"{{ $json.currentScreenshot }}\" alt=\"Current Screenshot\" style=\"width:100%; max-width:280px; border-radius:8px; border:1px solid #ddd; display:block;\">\n                  </td>\n                  <td align=\"center\" width=\"50%\" style=\"padding-left:5px;\">\n                    <p style=\"text-align:center; font-weight:bold; margin:0 0 5px 0;\">Last</p>\n                    <p style=\"text-align:center; font-size:12px; color:#888888; margin:0 0 10px 0;\">{{ $json.lastSnapshotDate }}</p>\n                    <img src=\"{{ $json.lastScreenshot }}\" alt=\"Last Screenshot\" style=\"width:100%; max-width:280px; border-radius:8px; border:1px solid #ddd; display:block;\">\n                  </td>\n                </tr>\n              </table>\n            </td>\n          </tr>\n          <tr>\n            <td>\n              <p style=\"color:#555555; line-height:1.5;\"><strong>Summary:</strong> {{ $json.summary }}</p>\n            </td>\n          </tr>\n          <tr>\n            <td align=\"center\" style=\"font-size:12px; color:#888888; margin-top:20px; padding-top:20px; border-top:1px solid #eee;\">\n              This is an automated alert for changes detected on your monitored website.\n            </td>\n          </tr>\n        </table>\n      </td>\n    </tr>\n  </table>\n</body>\n</html>",
        "options": {},
        "subject": "=Updates Detected on {{ $json.url.replace(\"https://\", \"\").replace(\"http://\", \"\") }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "64bb92fb-21a8-4d17-9990-40220c46c5a7",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -864,
        -352
      ],
      "parameters": {
        "width": 576,
        "height": 832,
        "content": "## How it works\nThis workflow monitors websites for changes automatically. It runs on a daily schedule to scrape target pages using Firecrawl, captures screenshots, and uses GPT-5-mini to compare new content against previous snapshots. Only meaningful changes (based on your criteria, like ignoring minor tweaks) are highlighted in summaries. Updates get saved to a Notion database for easy tracking, with optional email alerts via Gmail to notify you instantly.\n\nThe flow starts with a Schedule node, loops through your list of URLs, fetches and analyzes data, then stores or notifies as needed. It's scalable for multiple sites and keeps everything organized without manual checks.\n\n## Setup steps\n1. Import this template into n8n.\n2. In the \"Target URLs\" node (or input section), add your websites as a JSON array.\n3. Set up Firecrawl: Create an account at firecrawl.dev, get your API key, and add it as a credential in the Firecrawl nodes.\n4. Set up OpenAI: Get an API key from platform.openai.com, add it to the GPT node.\n5. For Notion storage: Ensure you have a database ready (duplicate the provided template), then add your Notion API key and database ID in the Notion nodes.\n6. For email alerts (optional): In the Gmail node, set up OAuth2 credentials via Google, and enter your recipient email.\n7. Define change criteria in the \"Change Criteria\" input, e.g., \"focus on pricing or product updates\".\n8. Test the workflow end-to-end, then enable the schedule for daily runs.\n\n\n**Need Help with This Template? Feel free to reach out. Our DMs are always open!**\n\n**Email:** [hello@scoutnow.app](mailto:hello@scoutnow.app)\n**X (Twitter):** [@ScoutNowApp](https://x.com/ScoutNowApp) \n\nNo question is too small. We\u2019re here to help!\n"
      },
      "typeVersion": 1
    },
    {
      "id": "7d8bfc00-c703-4dc7-8973-3a8341f8810b",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 2336,
        "height": 560,
        "content": "## 1. Capture a Snapshot Using Firecrawl\n\nUpdate the **Define** blocks below to set your target URLs and specify the type of update you want to perform.\n\nThe current target websites were intentionally chosen to demonstrate this workflow, as they change their content on every load.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "7558dfab-237d-45b9-bc80-40a4ca2810b1",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2352,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 1696,
        "height": 560,
        "content": "## 2. Save the Snapshot to the Notion Database\n\nUse the following page as your template: [Notion Page](https://scoutnow.notion.site/Track-Website-Changes-2b0c56764824800a993eca79f4b10bbf). It relies on two databases: one for storing snapshots and another for recording updates.\n\nWe split website content into multiple paragraph blocks because each block cannot exceed 2,000 characters.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "768381aa-ce83-4a28-b029-536aa7ea9c2a",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2352,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 1696,
        "height": 496,
        "content": "## 3. Compare the Snapshot with the Last Snapshot If Available"
      },
      "typeVersion": 1
    },
    {
      "id": "b1c69f7c-4b2f-45db-8c68-cf83bbd69e25",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4176,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 1872,
        "height": 496,
        "content": "## 4. Create an Update on Notion When Changes Are Detected\n\nWe use a custom Notion API to create column blocks and arrange screenshots side by side, \nsince the official Notion Node does not support columns.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "6a821c29-c4ae-42e2-b228-b1802ebf4368",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4176,
        -192
      ],
      "parameters": {
        "color": 7,
        "width": 1872,
        "height": 560,
        "content": "## 5. [Optional] Send an Email Alert\n\nSend an email alert when new updates are detected. You can remove this section if you don\u2019t need this functionality.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b907419c-6044-4adc-a26b-4b38116e71dc",
  "connections": {
    "Split Out": {
      "main": [
        [
          {
            "node": "Define What Matters To You",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Blocks": {
      "main": [
        []
      ]
    },
    "Create Updates": {
      "main": [
        [
          {
            "node": "Construct Update Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Snapshots": {
      "main": [
        [
          {
            "node": "Construct Notion Blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out Data": {
      "main": [
        [
          {
            "node": "Compare Snapshots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Many Blocks": {
      "main": [
        [
          {
            "node": "Combine Website Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Define Target URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out Blocks": {
      "main": [
        [
          {
            "node": "Append Blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Snapshots": {
      "main": [
        [
          {
            "node": "Combine Snapshots and AI Analysis",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Out Updates": {
      "main": [
        [
          {
            "node": "Create Updates",
            "type": "main",
            "index": 0
          },
          {
            "node": "Send Email Updates",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Define Target URLs": {
      "main": [
        [
          {
            "node": "Split Out",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Last Snapshots": {
      "main": [
        [
          {
            "node": "Get Many Blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Target URLs": {
      "main": [
        [
          {
            "node": "Capture Screenshots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Capture Screenshots": {
      "main": [
        [
          {
            "node": "Save Snapshots",
            "type": "main",
            "index": 0
          },
          {
            "node": "Get Last Snapshots",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Website Data": {
      "main": [
        [
          {
            "node": "Split Out Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Construct Notion Blocks": {
      "main": [
        [
          {
            "node": "Split Out Blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Define What Matters To You": {
      "main": [
        [
          {
            "node": "Scrape Target URLs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Combine Snapshots and AI Analysis": {
      "main": [
        [
          {
            "node": "Split Out Updates",
            "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

Manually checking websites for updates or competitor changes can be tedious. This workflow automates the process by scraping target pages, capturing screenshots, and analyzing content changes using Firecrawl and GPT-5-mini. All updates are saved in Notion, and you can optionally…

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

More Web Scraping workflows → · Browse all categories →

Related workflows

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

Web Scraping

📬 What This Workflow Does This workflow automatically scrapes recent high-value congressional stock trades from Quiver Quantitative, summarizes the key transactions, and delivers a neatly formatted re

HTTP Request, Gmail, OpenAI
Web Scraping

🔥 Daily Web Scraper & AI Summary with Firecrawl + Email Automation Need to extract and summarize web content from a site that doesn’t have an API? This workflow runs daily to scrape a web page using F

HTTP Request, Gmail, OpenAI
Web Scraping

This workflow is Part 2 of the HR Client Acquisition system and builds on the lead discovery pipeline from the previous workflow:

Google Sheets, HTTP Request, OpenAI +2
Web Scraping

This n8n template helps recruitment agencies discover active job openings, filter them based on hiring relevance, and qualify them using AI — specifically designed for semi-skilled manpower hiring use

Form Trigger, Google Sheets, OpenAI +2
Web Scraping

Schedule Trigger runs every 6 hours (customizable) Apify Scraper fetches Upwork jobs matching your criteria Deduplication filters out jobs you've already seen AI Scoring (GPT-4) evaluates fit, client

HTTP Request, Google Sheets, OpenAI +2