AutomationFlowsAI & RAG › Monitor Competitor Website Changes Weekly with Gpt-4.1-mini and Gmail

Monitor Competitor Website Changes Weekly with Gpt-4.1-mini and Gmail

ByMeet Soni @meet12 on n8n.io

How it works Runs automatically on a weekly schedule and fetches the live HTML of every competitor page you define Strips all HTML tags and captures a clean text snapshot of each page Compares the current snapshot against the previously stored version using workflow static data…

Cron / scheduled trigger★★★★☆ complexityAI-powered12 nodesHTTP RequestOpenAIGmail
AI & RAG Trigger: Cron / scheduled Nodes: 12 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #15429 — 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": "cQmkcbksmFo4quKl",
  "name": "Creator Template - Competitor Change Monitor",
  "tags": [],
  "nodes": [
    {
      "id": "35e2288f-23e2-4ce0-8930-42c61efcf093",
      "name": "Setup Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        -496
      ],
      "parameters": {
        "color": 5,
        "width": 902,
        "height": 1448,
        "content": "## \ud83d\udd75\ufe0f Competitor Change Monitor\n\nAutomatically tracks your competitors' websites on a weekly schedule, detects what changed, and delivers an AI-written intelligence digest as a Gmail draft \u2014 ready to share with your team.\n\n---\n\n## \u2699\ufe0f How It Works\n\n**1. Weekly Schedule**\nTriggers automatically once a week. You can adjust the frequency directly in the Schedule Trigger node.\n\n**2. Define Competitors**\nA Code node where you list the competitors you want to monitor. Each entry includes a `name`, `url`, and `watch_for` description (e.g. \"pricing changes\", \"new features\").\n\n**3. HTTP - Fetch Competitor Page**\nFetches the raw HTML of each competitor URL via an HTTP GET request. Runs once per competitor in the list.\n\n**4. Track Snapshot Changes**\nStrips all HTML tags, scripts, and styles down to clean readable text (up to 12,000 characters per page). Compares the current text against the last stored snapshot using n8n's built-in static data \u2014 no external database needed. Flags whether the page has `changed: true` or `false`.\n\n**5. Build Digest Prompt**\nCollects all changed pages and assembles a structured prompt for the AI. If nothing changed, it instructs the AI to produce a short no-change digest instead.\n\n**6. OpenAI - Summarize Competitor Changes**\nSends the prompt to GPT-4.1-mini which returns a plain-text competitive intelligence report covering:\n- Executive summary\n- Material changes by competitor\n- Suggested response actions\n- Watch items for the next run\n\n**7. Format Digest Email**\nFormats the AI output into an HTML email body and adds a date-stamped subject line like `Competitor change digest - 2026-05-01`.\n\n**8. Gmail - Draft Digest**\nSaves the formatted digest as a Gmail draft addressed to your recipient. Nothing is auto-sent \u2014 always review before sending.\n\n---\n\n## \ud83d\udd27 Setup Checklist\n\n- [ ] Open **Define Competitors** and add your competitor `name`, `url`, and `watch_for` values\n- [ ] Open **Build Digest Prompt** and replace `replace-me@example.com` with your recipient email\n- [x] Connect your **OpenAI** credential to the OpenAI node\n- [ ] Connect your **Gmail OAuth2** credential to the Gmail node\n- [ ] Run the workflow **once manually** to store the first baseline snapshots\n- [ ] **Activate** the workflow \u2014 weekly monitoring begins automatically\n\n---\n\n## \u26a0\ufe0f Things to Know\n\n- The **first run stores baselines only** \u2014 no digest is generated until the second run detects a diff\n- Snapshots are stored in **n8n workflow static data** \u2014 clearing static data resets all baselines\n- Page text is capped at `12,000` characters per competitor to stay within token limits\n- Sites with heavy JavaScript rendering may return incomplete snapshots via HTTP \u2014 consider a headless browser node for those\n- Adjust the schedule in the **Weekly Schedule** node to run daily or bi-weekly as needed"
      },
      "typeVersion": 1
    },
    {
      "id": "f9e987b2-ca04-4561-88ca-7099f89e0ff3",
      "name": "Weekly Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        848,
        96
      ],
      "parameters": {
        "rule": {
          "interval": [
            {}
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "0243b60b-bb28-4756-88de-4c6bab7b2c54",
      "name": "Define Competitors",
      "type": "n8n-nodes-base.code",
      "position": [
        1088,
        96
      ],
      "parameters": {
        "jsCode": "// Replace this array with your competitors, pricing pages, changelog URLs, or product pages.\nconst competitors = [\n  { name: \"Competitor A\", url: \"https://example.com/pricing\", watch_for: \"pricing, plans, positioning\" },\n  { name: \"Competitor B\", url: \"https://example.org/features\", watch_for: \"features, integrations, headline changes\" }\n];\n\nreturn competitors.map((competitor) => ({ json: competitor }));"
      },
      "typeVersion": 2
    },
    {
      "id": "db802d84-744c-427f-a060-0c98dd417f61",
      "name": "HTTP - Fetch Competitor Page",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1360,
        96
      ],
      "parameters": {
        "url": "={{ .url }}",
        "options": {
          "timeout": 20000,
          "redirect": {}
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "9d3166d3-c737-4957-a4a0-c463ec2abdc3",
      "name": "Track Snapshot Changes",
      "type": "n8n-nodes-base.code",
      "position": [
        1616,
        96
      ],
      "parameters": {
        "jsCode": "const page = $json.body || $json.data || $json.html || JSON.stringify($json);\nconst text = String(page)\n  .replace(/<script[\\s\\S]*?<\\/script>/gi, \" \")\n  .replace(/<style[\\s\\S]*?<\\/style>/gi, \" \")\n  .replace(/<[^>]+>/g, \" \")\n  .replace(/\\s+/g, \" \")\n  .trim()\n  .slice(0, 12000);\n\nconst staticData = $getWorkflowStaticData(\"global\");\nstaticData.snapshots = staticData.snapshots || {};\n\nconst key = $json.url;\nconst previous = staticData.snapshots[key];\nstaticData.snapshots[key] = {\n  captured_at: new Date().toISOString(),\n  text\n};\n\nconst changed = !previous || previous.text !== text;\n\nreturn [{\n  json: {\n    name: $json.name,\n    url: $json.url,\n    watch_for: $json.watch_for,\n    changed,\n    previous_text: previous?.text || \"\",\n    current_text: text,\n    captured_at: staticData.snapshots[key].captured_at\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "4c6b1a0c-8a50-442d-9846-935bdf7c82e5",
      "name": "Build Digest Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        1872,
        96
      ],
      "parameters": {
        "jsCode": "const items = $input.all().map((item) => item.json);\nconst changed = items.filter((item) => item.changed);\n\nconst prompt = changed.length\n  ? changed.map((item) => [\n      `COMPETITOR: ${item.name}`,\n      `URL: ${item.url}`,\n      `WATCH FOR: ${item.watch_for}`,\n      `PREVIOUS SNAPSHOT:\\n${item.previous_text || \"(first run - no previous snapshot)\"}`,\n      `CURRENT SNAPSHOT:\\n${item.current_text}`\n    ].join(\"\\n\")).join(\"\\n\\n---\\n\\n\")\n  : \"No competitors changed since the last run. Create a short no-change digest.\";\n\nreturn [{\n  json: {\n    changed_count: changed.length,\n    total_checked: items.length,\n    prompt,\n    recipient_email: \"user@example.com\"\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "b795e60b-4cd5-467c-9e7e-838c85333012",
      "name": "OpenAI - Summarize Competitor Changes",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        2080,
        96
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "gpt-4.1-mini"
        },
        "options": {
          "temperature": 0.2
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a concise competitive intelligence analyst. Return a practical email digest in plain text. No markdown tables."
            },
            {
              "content": "=Checked {{ $json.total_checked }} competitors. Changed pages: {{ $json.changed_count }}.\n\nAnalyze the snapshots below. Focus on pricing, positioning, offers, product launches, feature changes, and possible sales/marketing implications.\n\n{{ $json.prompt }}\n\nWrite:\n1. Executive summary\n2. Material changes by competitor\n3. Suggested response actions\n4. Watch items for next run"
            }
          ]
        }
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "f4bfb978-9066-4746-82f4-46b34daa4d61",
      "name": "Format Digest Email",
      "type": "n8n-nodes-base.code",
      "position": [
        2400,
        96
      ],
      "parameters": {
        "jsCode": "const raw = $json.message?.content || $json.text || \"\";\nconst now = new Date().toISOString().slice(0, 10);\nreturn [{\n  json: {\n    subject: `Competitor change digest - ${now}`,\n    digest_html: raw.replace(/\\n/g, \"<br>\"),\n    recipient_email: $(\"Build Digest Prompt\").first().json.recipient_email,\n    changed_count: $(\"Build Digest Prompt\").first().json.changed_count,\n    total_checked: $(\"Build Digest Prompt\").first().json.total_checked\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "1e0f679f-b47f-4446-bbe7-d36e6bc9b815",
      "name": "Gmail - Draft Digest",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2656,
        96
      ],
      "parameters": {
        "message": "={{ .digest_html }}",
        "options": {
          "sendTo": "={{ .recipient_email }}"
        },
        "subject": "={{ .subject }}",
        "resource": "draft",
        "emailType": "html"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6a3ed7a9-3b32-4225-bedd-c71b3c9a40b5",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        832,
        32
      ],
      "parameters": {
        "color": 5,
        "width": 688,
        "height": 256,
        "content": "## Fetch competitor "
      },
      "typeVersion": 1
    },
    {
      "id": "ee25ad0d-0e4b-44d8-88ef-29a86ad7831d",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1568,
        0
      ],
      "parameters": {
        "color": 5,
        "width": 464,
        "height": 272,
        "content": "## Track the changes and build digest accordingly"
      },
      "typeVersion": 1
    },
    {
      "id": "4d477952-891e-4513-859d-bf18810e5eac",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        0
      ],
      "parameters": {
        "color": 5,
        "width": 800,
        "height": 272,
        "content": "## Build and send the digest through Email"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "b5dde8e2-42d1-4e70-8967-877eeb8d76cf",
  "connections": {
    "Weekly Schedule": {
      "main": [
        [
          {
            "node": "Define Competitors",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Define Competitors": {
      "main": [
        [
          {
            "node": "HTTP - Fetch Competitor Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Digest Prompt": {
      "main": [
        [
          {
            "node": "OpenAI - Summarize Competitor Changes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Digest Email": {
      "main": [
        [
          {
            "node": "Gmail - Draft Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Track Snapshot Changes": {
      "main": [
        [
          {
            "node": "Build Digest Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP - Fetch Competitor Page": {
      "main": [
        [
          {
            "node": "Track Snapshot Changes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI - Summarize Competitor Changes": {
      "main": [
        [
          {
            "node": "Format Digest Email",
            "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

How it works Runs automatically on a weekly schedule and fetches the live HTML of every competitor page you define Strips all HTML tags and captures a clean text snapshot of each page Compares the current snapshot against the previously stored version using workflow static data…

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

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
AI & RAG

This workflow monitors filesystem sync and backup jobs by validating their execution logs, not by running or inspecting the jobs themselves.

Google Cloud Storage, Gmail, GitHub +2
AI & RAG

Stop wasting billable hours on manual time-tracking. AutoTimesheet Pro uses AI to collect emails, meetings, and GitHub work, then writes a clean timesheet straight into Google Sheets. Perfect for deve

Google Calendar, Gmail, GitHub +3
AI & RAG

Imagine a dedicated financial expert tirelessly working behind the scenes, sifting through every transaction, every investment move, and every accounting entry. That's exactly what this automated syst

HTTP Request, Google Sheets, OpenAI +3
AI & RAG

Who is this for? AI creators, marketers, agencies, and researchers tracking YouTube trends who need weekly high-signal insights without 4+ hours manual research.

HTTP Request, OpenAI, Google Sheets +2