{
  "id": "zewdHLI58e4MieOE",
  "name": "SEO & Competitor Intelligence Reporting Pipeline",
  "tags": [],
  "nodes": [
    {
      "id": "b283d21a-17e3-459a-b948-3cd0df10a668",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        -48
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 1612,
        "content": "## \ud83d\udcc8 SEO & Competitor Intelligence Reporting Pipeline\n\nEvery Monday morning, this workflow pulls competitor and search performance data from SEMrush, Google Analytics 4, and a tracked competitor's webpage, then uses AI to summarize the biggest ranking movements, traffic anomalies, and competitor changes into a report delivered by email and Slack.\n\n**Perfect for:** SEO teams, marketing agencies, or in-house growth teams who need a recurring competitive intelligence briefing without manually pulling reports from multiple tools.\n\n---\n\n## How it works\n\n1. **Every Monday 7am** \u2014 Triggers the pipeline on a weekly schedule.\n2. **Fetch SEMrush Rankings** \u2014 Pulls organic keyword rankings and positions for the tracked domain.\n3. **Fetch GA4 Traffic** \u2014 Retrieves the last 7 days of landing page sessions and organic search clicks from Google Analytics 4.\n4. **Scrape Competitor Pages** \u2014 Downloads the raw HTML of a tracked competitor page. *(continues on failure so one bad scrape doesn't stop the report)*\n5. **Combine Intelligence** \u2014 Merges the SEMrush, GA4, and competitor scrape outputs into a single item.\n6. **Compute Movers & Anomalies** \u2014 Hashes the competitor page HTML and compares it to last week's stored hash to detect whether the competitor's page changed.\n7. **Summarize Movers (AI Agent)** \u2014 Turns the combined data into a 4-5 sentence plain-language summary, calling out the single most important action item.\n8. **OpenAI Chat Model** \u2014 Supplies the language model (GPT-5 mini) that powers the Summarize Movers agent.\n9. **Email Report** \u2014 Sends the AI-written summary as an HTML email to the client.\n10. **Post to Slack** \u2014 Posts the same summary to a Slack channel for the internal team.\n11. **Error Trigger** \u2014 Catches any failure in the pipeline. *(error-handling path)*\n12. **Notify Ops** \u2014 Posts a failure alert with the error message to an ops Slack channel.\n\n---\n\n## Setup (~10 minutes)\n\n1. **SEMrush API** \u2014 Add your API key in the *Fetch SEMrush Rankings* node and set the domain to track.\n2. **Google Analytics 4** \u2014 Add your GA4 credential in the *Fetch GA4 Traffic* node and replace `YOUR_GA4_PROPERTY_ID` in the URL.\n3. **Competitor URL** \u2014 Replace the placeholder URL in the *Scrape Competitor Pages* node with the page you want to monitor.\n4. **OpenAI** \u2014 Add your OpenAI API key in the *OpenAI Chat Model* node.\n5. **Gmail** \u2014 Connect your Gmail account in the *Email Report* node and set the client's email address.\n6. **Slack** \u2014 Connect your Slack account and set the channel IDs in *Post to Slack* and *Notify Ops*.\n> Competitor scraping may break if the target site blocks bots or changes its HTML structure \u2014 check the *Scrape Competitor Pages* node if change detection stops firing."
      },
      "typeVersion": 1
    },
    {
      "id": "00432661-fde0-4c90-82eb-003af26e2e39",
      "name": "Section: Trigger & Data Intake",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -96,
        -96
      ],
      "parameters": {
        "color": 5,
        "width": 584,
        "height": 876,
        "content": "## 1\ufe0f\u20e3 Trigger & Data Intake\n\nEvery Monday at 7am the **Every Monday 7am** schedule trigger kicks off three parallel data pulls: **Fetch SEMrush Rankings** for keyword position data, **Fetch GA4 Traffic** for the past week's organic sessions and clicks, and **Scrape Competitor Pages** for the raw HTML of a tracked competitor page."
      },
      "typeVersion": 1
    },
    {
      "id": "5c5c4fa2-65e6-4b7a-995d-d2c6472d9094",
      "name": "Section: Analysis & AI Summary",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        544,
        -16
      ],
      "parameters": {
        "color": 3,
        "width": 920,
        "height": 648,
        "content": "## 2\ufe0f\u20e3 Analysis & AI Summary\n\n**Combine Intelligence** merges the three data sources into one item, then **Compute Movers & Anomalies** hashes the competitor HTML to flag whether it changed since last week. The **Summarize Movers (AI Agent)**, powered by the **OpenAI Chat Model**, turns the combined data into a plain-language summary highlighting the biggest movers and the top action item."
      },
      "typeVersion": 1
    },
    {
      "id": "2a4e1180-f1e9-48c9-90d8-ba550c1d4ed8",
      "name": "Section: Report Delivery",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        -32
      ],
      "parameters": {
        "color": 4,
        "width": 380,
        "height": 636,
        "content": "## 3\ufe0f\u20e3 Report Delivery\n\nThe AI-generated summary is delivered two ways: **Email Report** sends it as an HTML email to the client, and **Post to Slack** posts the same summary into an internal Slack channel."
      },
      "typeVersion": 1
    },
    {
      "id": "d5f851bd-5df4-42a1-b2f1-5bbc8d3c5e2e",
      "name": "Section: Error Handling",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        1056
      ],
      "parameters": {
        "color": 6,
        "width": 584,
        "height": 420,
        "content": "## 4\ufe0f\u20e3 Error Handling\n\nIf any step in the pipeline fails, the **Error Trigger** fires and **Notify Ops** posts an alert with the error message to an internal ops Slack channel, so failures are caught immediately instead of silently skipping the week's report."
      },
      "typeVersion": 1
    },
    {
      "id": "9c4b6666-e138-44b0-9b7c-b6be41af3bfe",
      "name": "Every Monday 7am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -64,
        304
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 7
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "3a6d1fd4-f7d6-4ec2-b628-85be42de723d",
      "name": "Fetch SEMrush Rankings",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 3,
      "position": [
        192,
        160
      ],
      "parameters": {
        "url": "https://api.semrush.com/",
        "options": {
          "timeout": 15000
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "type",
              "value": "domain_organic"
            },
            {
              "name": "domain",
              "value": "REPLACE_WITH_DOMAIN"
            },
            {
              "name": "export_columns",
              "value": "Ph,Po,Pp,Nq,Ur"
            }
          ]
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "2aa846f4-b0ba-4ce6-b5e7-c24bf2a36ad3",
      "name": "Fetch GA4 Traffic",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 3,
      "position": [
        176,
        320
      ],
      "parameters": {
        "url": "https://analyticsdata.googleapis.com/v1beta/properties/YOUR_GA4_PROPERTY_ID:runReport",
        "method": "POST",
        "options": {
          "timeout": 15000
        },
        "jsonBody": "={{ { dateRanges: [{ startDate: \"7daysAgo\", endDate: \"today\" }], dimensions: [{ name: \"landingPagePlusQueryString\" }], metrics: [{ name: \"sessions\" }, { name: \"organicGoogleSearchClicks\" }] } }}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "e224fae6-12e1-4978-8ff4-522856c8b19f",
      "name": "Scrape Competitor Pages",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 2,
      "position": [
        176,
        512
      ],
      "parameters": {
        "url": "=REPLACE_WITH_COMPETITOR_URL",
        "options": {
          "timeout": 15000,
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "ba6aaff8-09b3-4434-9218-59b496b2384a",
      "name": "Combine Intelligence",
      "type": "n8n-nodes-base.merge",
      "position": [
        624,
        224
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineAll"
      },
      "typeVersion": 3.2
    },
    {
      "id": "cedd8113-1584-4ec8-b76a-f9dbee49b60a",
      "name": "Compute Movers & Anomalies",
      "type": "n8n-nodes-base.code",
      "position": [
        928,
        224
      ],
      "parameters": {
        "jsCode": "const staticData = $getWorkflowStaticData('global');\nconst semrush = $('Fetch SEMrush Rankings').first()?.json || {};\nconst ga4 = $('Fetch GA4 Traffic').first()?.json || {};\nconst competitorHtml = $('Scrape Competitor Pages').first()?.json?.data || '';\nconst competitorHash = require('crypto').createHash('md5').update(String(competitorHtml)).digest('hex');\nconst previousHash = staticData.lastCompetitorHash;\nconst competitorChanged = previousHash ? previousHash !== competitorHash : false;\nstaticData.lastCompetitorHash = competitorHash;\nreturn [{ json: { semrush, ga4, competitorChanged } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "6c460056-0468-4cdb-8564-bd9556763797",
      "name": "Summarize Movers (AI Agent)",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1152,
        224
      ],
      "parameters": {
        "text": "=SEO data this week: {{ JSON.stringify($json) }}",
        "options": {
          "systemMessage": "You are an SEO analyst. Summarize the biggest ranking movers, traffic anomalies, and whether a competitor page changed, in 4-5 plain-language sentences suitable for a Monday morning report. Call out the single most important thing to act on."
        },
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "42643154-d4f5-4a55-b08f-4bb007184433",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1216,
        464
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini"
        },
        "options": {
          "temperature": 0.4
        },
        "builtInTools": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "5a989fbe-265f-40f0-9663-81d4c0696dd9",
      "name": "Email Report",
      "type": "n8n-nodes-base.gmail",
      "maxTries": 2,
      "position": [
        1744,
        192
      ],
      "parameters": {
        "sendTo": "client@REPLACE_WITH_CLIENT_DOMAIN.com",
        "message": "={{ '<p>' + $json.output.replace(/\\n/g, '<br>') + '</p>' }}",
        "options": {
          "appendAttribution": false
        },
        "subject": "=Weekly SEO & Competitor Intelligence \u2014 {{ $now.toFormat('dd LLL yyyy') }}"
      },
      "retryOnFail": true,
      "typeVersion": 2.1
    },
    {
      "id": "5ee03a4a-d403-4522-bdab-0b4c608f0b87",
      "name": "Post to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1744,
        400
      ],
      "parameters": {
        "text": "=\ud83d\udcc8 Weekly SEO Report:\\n{{ $json.output }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_CHANNEL_ID",
          "cachedResultName": "seo-reports"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "11b01c8b-7736-4f7f-8c7d-6ede1272b034",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        0,
        1248
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "1627d816-5346-435d-be62-ec979e62b74f",
      "name": "Notify Ops",
      "type": "n8n-nodes-base.slack",
      "position": [
        240,
        1248
      ],
      "parameters": {
        "text": "=\ud83d\udea8 SEO & Competitor Intelligence Pipeline failed: {{ $json.execution.error.message }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_CHANNEL_ID",
          "cachedResultName": "ops-alerts"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "1a27287d-6e65-4966-a4e8-b2177597200c",
  "nodeGroups": [],
  "connections": {
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Notify Ops",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Monday 7am": {
      "main": [
        [
          {
            "node": "Fetch SEMrush Rankings",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch GA4 Traffic",
            "type": "main",
            "index": 0
          },
          {
            "node": "Scrape Competitor Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GA4 Traffic": {
      "main": [
        [
          {
            "node": "Combine Intelligence",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Summarize Movers (AI Agent)",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Combine Intelligence": {
      "main": [
        [
          {
            "node": "Compute Movers & Anomalies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch SEMrush Rankings": {
      "main": [
        [
          {
            "node": "Combine Intelligence",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compute Movers & Anomalies": {
      "main": [
        [
          {
            "node": "Summarize Movers (AI Agent)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Summarize Movers (AI Agent)": {
      "main": [
        [
          {
            "node": "Email Report",
            "type": "main",
            "index": 0
          },
          {
            "node": "Post to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}