AutomationFlowsSlack & Telegram › Daily Google Search Console SEO Pulse: Catch Top Movers Across Keyword Segments

Daily Google Search Console SEO Pulse: Catch Top Movers Across Keyword Segments

ByMattF @the-curious-automator on n8n.io

Instead of serving as a routine check, it highlights the queries and pages with the biggest jumps or drops, making it ideal for spotting wins, losses, or unexpected shifts early. Runs daily on a scheduled trigger (e.g. every morning). Pulls GSC data for the prior two days (e.g.…

Cron / scheduled trigger★★★★☆ complexity25 nodesHTTP RequestSlack
Slack & Telegram Trigger: Cron / scheduled Nodes: 25 Complexity: ★★★★☆ Added:
Daily Google Search Console SEO Pulse: Catch Top Movers Across Keyword Segments — n8n workflow card showing HTTP Request, Slack integration

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

This workflow follows the HTTP Request → 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": "p52nkbZfBVrRJyKq",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Daily GSC Pulse Check - Generic",
  "tags": [
    {
      "id": "10",
      "name": "SEO",
      "createdAt": "2022-11-25T12:57:02.999Z",
      "updatedAt": "2022-11-25T12:57:02.999Z"
    },
    {
      "id": "dO9obbaAMg8UNnbo",
      "name": "Scheduled",
      "createdAt": "2025-07-10T15:12:41.643Z",
      "updatedAt": "2025-07-10T15:12:41.643Z"
    }
  ],
  "nodes": [
    {
      "id": "46510a4e-92b5-427c-849e-2508b849d37e",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "notes": "Splits the day flows",
      "position": [
        100,
        2100
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8ab18755-9c4f-40d8-a0c0-f16ab3b7d940",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.label }}",
              "rightValue": "priorDay"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.2
    },
    {
      "id": "a5db86b4-8046-4348-8521-01e5c6606ce2",
      "name": "label",
      "type": "n8n-nodes-base.code",
      "position": [
        420,
        2020
      ],
      "parameters": {
        "jsCode": "return items.map(item => {\n  return {\n    json: {\n      day: \"priorDay\",  // or \"lastDay\" in the other branch\n      ...item.json        // preserve everything from GSC response\n    }\n  };\n});\n"
      },
      "notesInFlow": false,
      "typeVersion": 2
    },
    {
      "id": "e69229e9-8f8c-41ad-9251-000ec693dabe",
      "name": "label1",
      "type": "n8n-nodes-base.code",
      "position": [
        420,
        2180
      ],
      "parameters": {
        "jsCode": "return items.map(item => {\n  return {\n    json: {\n      day: \"lastDay\",  // or \"priorDay\" in the other branch\n      ...item.json        // preserve everything from GSC response\n    }\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "51f0a2bc-84d2-4bba-bdac-e80dcfe5c4c3",
      "name": "Flatten",
      "type": "n8n-nodes-base.code",
      "position": [
        560,
        2020
      ],
      "parameters": {
        "jsCode": "const dayLabel = $json.day;\n\nif (!items[0].json.rows) {\n  return [];\n}\n\nreturn items[0].json.rows.map(row => {\n  return {\n    json: {\n      day: dayLabel,\n      page: row.keys[0] || null,\n      query: row.keys[1] || null,\n      clicks: row.clicks,\n      impressions: row.impressions,\n      ctr: row.ctr,\n      position: row.position\n    }\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "e625c5a3-af33-4e1d-83ed-d6aecb4d12d2",
      "name": "Flatten1",
      "type": "n8n-nodes-base.code",
      "position": [
        560,
        2180
      ],
      "parameters": {
        "jsCode": "const dayLabel = $json.day;\n\nif (!items[0].json.rows) {\n  return [];\n}\n\nreturn items[0].json.rows.map(row => {\n  return {\n    json: {\n      day: dayLabel,\n      page: row.keys[0] || null,\n      query: row.keys[1] || null,\n      clicks: row.clicks,\n      impressions: row.impressions,\n      ctr: row.ctr,\n      position: row.position\n    }\n  };\n});\n"
      },
      "typeVersion": 2
    },
    {
      "id": "c03f6440-6c92-4410-b992-13015dfc151c",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        740,
        2100
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "8e86e0c5-1e43-4df2-b80d-3439a37f56b7",
      "name": "Top Movers Filter",
      "type": "n8n-nodes-base.code",
      "notes": "Set alert threshold by DoD delta clicks & % change",
      "position": [
        1420,
        1860
      ],
      "parameters": {
        "jsCode": "const flagged = [];\n\nfor (const item of items) {\n  const delta = item.json.deltaClicks || 0;\n  const pct = parseFloat(item.json.percentChangeClicks?.replace('%', '') || 0);\n\n  if (Math.abs(delta) >= 100 && Math.abs(pct) >= 30) {\n    const direction = delta > 0 ? '\ud83d\udcc8 UP' : '\ud83d\udcc9 DOWN';\n    const line = `\u2022 ${direction} ${item.json.query} \u2192 ${delta > 0 ? '+' : ''}${delta} clicks (${item.json.percentChangeClicks})\\nPage: ${item.json.page}`;\n    \n    flagged.push(line);\n  }\n}\n\nif (flagged.length === 0) {\n  return []; // No alerts to send\n}\n\nreturn [\n  {\n    json: {\n      text: `*\ud83d\udea8\ud83d\udea8 Big DoD Movers Alert - BRAND:*\\n\\n${flagged.join('\\n\\n')}`\n    }\n  }\n];\n"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "a28c35e9-222b-4b7a-a9ca-533cfd4e0258",
      "name": "Top Movers Filter1",
      "type": "n8n-nodes-base.code",
      "notes": "Set alert threshold by DoD delta clicks & % change",
      "position": [
        1420,
        2020
      ],
      "parameters": {
        "jsCode": "const flagged = [];\n\nfor (const item of items) {\n  const delta = item.json.deltaClicks || 0;\n  const pct = parseFloat(item.json.percentChangeClicks?.replace('%', '') || 0);\n\n  if (Math.abs(delta) >= 100 && Math.abs(pct) >= 30) {\n    const direction = delta > 0 ? '\ud83d\udcc8 UP' : '\ud83d\udcc9 DOWN';\n    const line = `\u2022 ${direction} ${item.json.query} \u2192 ${delta > 0 ? '+' : ''}${delta} clicks (${item.json.percentChangeClicks})\\nPage: ${item.json.page}`;\n    \n    flagged.push(line);\n  }\n}\n\nif (flagged.length === 0) {\n  return []; // No alerts to send\n}\n\nreturn [\n  {\n    json: {\n      text: `*\ud83d\udea8\ud83d\udea8 Big DoD Movers Alert - BRAND + RECIPES:*\\n\\n${flagged.join('\\n\\n')}`\n    }\n  }\n];\n"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "46c53f69-df74-4501-93ee-2489d1b9b422",
      "name": "Top Movers Filter2",
      "type": "n8n-nodes-base.code",
      "notes": "Set alert threshold by DoD delta clicks & % change",
      "position": [
        1420,
        2180
      ],
      "parameters": {
        "jsCode": "const flagged = [];\n\nfor (const item of items) {\n  const delta = item.json.deltaClicks || 0;\n  const pct = parseFloat(item.json.percentChangeClicks?.replace('%', '') || 0);\n\n  if (Math.abs(delta) >= 100 && Math.abs(pct) >= 30) {\n    const direction = delta > 0 ? '\ud83d\udcc8 UP' : '\ud83d\udcc9 DOWN';\n    const line = `\u2022 ${direction} ${item.json.query} \u2192 ${delta > 0 ? '+' : ''}${delta} clicks (${item.json.percentChangeClicks})\\nPage: ${item.json.page}`;\n    \n    flagged.push(line);\n  }\n}\n\nif (flagged.length === 0) {\n  return []; // No alerts to send\n}\n\nreturn [\n  {\n    json: {\n      text: `*\ud83d\udea8\ud83d\udea8 Big DoD Movers Alert - RECIPES:*\\n\\n${flagged.join('\\n\\n')}`\n    }\n  }\n];\n"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "44e48299-1c30-4424-ac44-6ea4ed8d83f2",
      "name": "Top Movers Filter3",
      "type": "n8n-nodes-base.code",
      "notes": "Set alert threshold by DoD delta clicks & % change",
      "position": [
        1420,
        2340
      ],
      "parameters": {
        "jsCode": "const flagged = [];\n\nfor (const item of items) {\n  const delta = item.json.deltaClicks || 0;\n  const pct = parseFloat(item.json.percentChangeClicks?.replace('%', '') || 0);\n\n  if (Math.abs(delta) >= 100 && Math.abs(pct) >= 30) {\n    const direction = delta > 0 ? '\ud83d\udcc8 UP' : '\ud83d\udcc9 DOWN';\n    const line = `\u2022 ${direction} ${item.json.query} \u2192 ${delta > 0 ? '+' : ''}${delta} clicks (${item.json.percentChangeClicks})\\nPage: ${item.json.page}`;\n    \n    flagged.push(line);\n  }\n}\n\nif (flagged.length === 0) {\n  return []; // No alerts to send\n}\n\nreturn [\n  {\n    json: {\n      text: `*\ud83d\udea8 Big DoD Movers Alert - NONBRAND:*\\n\\n${flagged.join('\\n\\n')}`\n    }\n  }\n];\n"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "2a37965c-bd16-4ac9-baaf-829198889cc0",
      "name": "Schedule Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -220,
        2100
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 15 * * 1-5"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "66f25e9c-25a7-49f8-a047-0c4bbf3d677e",
      "name": "priorDay",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Connect to GSC account",
      "position": [
        280,
        2020
      ],
      "parameters": {
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"startDate\": \"{{ $json.startDate }}\",\n  \"endDate\": \"{{ $json.endDate }}\",\n  \"dimensions\": [\"page\", \"query\"],\n  \"rowLimit\": 2500,\n  \"dataState\": \"all\"\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleOAuth2Api"
      },
      "credentials": {
        "googleOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "a439c73a-47ee-41e1-b877-d12df7afa4d6",
      "name": "lastDay",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Connect to GSC account",
      "position": [
        280,
        2180
      ],
      "parameters": {
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"startDate\": \"{{ $json.startDate }}\",\n  \"endDate\": \"{{ $json.endDate }}\",\n  \"dimensions\": [\"page\", \"query\"],\n  \"rowLimit\": 2500,\n  \"dataState\": \"all\"\n}\n",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleOAuth2Api"
      },
      "credentials": {
        "googleOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.2
    },
    {
      "id": "cb5f28bb-a105-4cee-b9ed-3ed9c4010abf",
      "name": "Top DoD Movers Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        1600,
        1860
      ],
      "parameters": {
        "text": "={{$json.text}}",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "c96ab11d-0dc4-439e-90b3-1f322c8870b8",
      "name": "Top DoD Movers Alert1",
      "type": "n8n-nodes-base.slack",
      "position": [
        1600,
        2020
      ],
      "parameters": {
        "text": "={{$json.text}}",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "48cb64c5-8d42-49d1-87c9-1add5cd313bf",
      "name": "Top DoD Movers Alert2",
      "type": "n8n-nodes-base.slack",
      "position": [
        1600,
        2180
      ],
      "parameters": {
        "text": "={{$json.text}}",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "bcd61d44-9317-4093-9b17-1936722b6f16",
      "name": "Top DoD Movers Alert3",
      "type": "n8n-nodes-base.slack",
      "position": [
        1600,
        2340
      ],
      "parameters": {
        "text": "={{$json.text}}",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "select": "user",
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "ba309af5-59c4-4604-8877-f4c02d33769f",
      "name": "Tag KWs by Category",
      "type": "n8n-nodes-base.code",
      "notes": "Create KW segment",
      "position": [
        1020,
        2100
      ],
      "parameters": {
        "jsCode": "// Step 1: Map the items and add properties\nconst mappedItems = items.map(item => {\n  const query = (item.json.query || \"\").toLowerCase();\n  const page = (item.json.page || \"\").toLowerCase();\n\n  // Update with your own brand terms\"\n  const isBrand = query.includes(\"BRAND TERM 1\", \"BRAND TERM 2\", \"ETC.\");\n  // Remove if you don't want to also segment brand terms by page group, or update with your own group, or add more as needed\n  const isRecipes = page.includes(\"/recipes\");\n\n  // Tag segment type \u2014 this is optional now that isBrand + isRecipes can coexist\n  let segment = \"nonbrand\";\n  if (isBrand && isRecipes) {\n    segment = \"brand+recipes\";\n  } else if (isBrand) {\n    segment = \"brand\";\n  } else if (isRecipes) {\n    segment = \"recipes\";\n  }\n\n  return {\n    json: {\n      ...item.json,\n      isBrand,\n      isRecipes,\n      segment\n    }\n  };\n});\n\n// Step 2: Sort by deltaClicks\nconst sortedItems = mappedItems.sort((a, b) => {\n  const deltaClicksA = a.json.deltaClicks || 0;\n  const deltaClicksB = b.json.deltaClicks || 0;\n\n  // Sorting in descending order (highest deltaClicks first)\n  return deltaClicksB - deltaClicksA;\n});\n\n// Return the sorted items\nreturn sortedItems;\n"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "1fd6facd-a9e9-41c8-85a8-740754566523",
      "name": "Define Days",
      "type": "n8n-nodes-base.code",
      "notes": "Defines what the days are",
      "position": [
        -60,
        2100
      ],
      "parameters": {
        "jsCode": "function formatDate(date) {\n  return date.toISOString().split('T')[0];\n}\n\nconst today = new Date();\nconst prior = new Date(today);\nprior.setDate(today.getDate() - 2);\nconst last = new Date(today);\nlast.setDate(today.getDate() - 1);\n\nreturn [\n  { json: { label: 'priorDay', startDate: formatDate(prior), endDate: formatDate(prior) } },\n  { json: { label: 'lastDay', startDate: formatDate(last), endDate: formatDate(last) } }\n];"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "a33e7206-32fc-478a-853e-1927ea851561",
      "name": "Merge Days",
      "type": "n8n-nodes-base.code",
      "position": [
        880,
        2100
      ],
      "parameters": {
        "jsCode": "// Split all items by day\nconst prior = [];\nconst last = [];\n\nfor (const item of items) {\n  if (item.json.day === \"priorDay\") {\n    prior.push(item.json);\n  } else if (item.json.day === \"lastDay\") {\n    last.push(item.json);\n  }\n}\n\n// Index prior day rows by page+query\nconst priorMap = new Map();\nfor (const row of prior) {\n  const key = `${row.page}|||${row.query}`;\n  priorMap.set(key, row);\n}\n\n// Match last day rows and compute deltas + formatted % changes\nconst results = [];\n\nfor (const row of last) {\n  const key = `${row.page}|||${row.query}`;\n  const previous = priorMap.get(key);\n  if (!previous) continue;\n\n  const clicksDelta = row.clicks - previous.clicks;\n  const ctrDeltaRaw = row.ctr - previous.ctr;\n  const impressionsDelta = row.impressions - previous.impressions;\n  const positionDelta = row.position - previous.position;\n\n  const percentChangeClicks = previous.clicks !== 0 ? `${((clicksDelta / previous.clicks) * 100).toFixed(1)}%` : null;\n  const percentChangeCTR = previous.ctr !== 0 ? `${((ctrDeltaRaw / previous.ctr) * 100).toFixed(1)}%` : null;\n  const percentChangeImpressions = previous.impressions !== 0 ? `${((impressionsDelta / previous.impressions) * 100).toFixed(1)}%` : null;\n  const percentChangePosition = previous.position !== 0 ? `${((positionDelta / previous.position) * 100).toFixed(1)}%` : null;\n\n  const ctrLastDay = `${(row.ctr * 100).toFixed(1)}%`;\n  const ctrPriorDay = `${(previous.ctr * 100).toFixed(1)}%`;\n  const deltaCTR = `${(ctrDeltaRaw * 100).toFixed(1)}%`;\n\n  results.push({\n    json: {\n      page: row.page,\n      query: row.query,\n\n      deltaClicks: clicksDelta,\n      percentChangeClicks,\n      clicksLastDay: row.clicks,\n      clicksPriorDay: previous.clicks,\n\n      deltaCTR,\n      percentChangeCTR,\n      ctrLastDay,\n      ctrPriorDay,\n\n      deltaImpressions: impressionsDelta,\n      percentChangeImpressions,\n      impressionsLastDay: row.impressions,\n      impressionsPriorDay: previous.impressions,\n\n      deltaPosition: positionDelta,\n      percentChangePosition,\n      positionLastDay: row.position,\n      positionPriorDay: previous.position\n    }\n  });\n}\n\nreturn results;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "6cea0ab7-6d2a-4e9a-aeb3-edc36054aeaa",
      "name": "Segment Switch",
      "type": "n8n-nodes-base.switch",
      "notes": "Divide segments into flows",
      "position": [
        1160,
        2080
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Brand Flow",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.segment }}",
                    "rightValue": "brand"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Brand+Recipes Flow",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "84a4654e-3d07-4bde-a7cf-aadf9b61301d",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.segment }}",
                    "rightValue": "brand+recipes"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Recipes Flow",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "eee379f6-8678-4f7c-8fb4-68a0be79aa01",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.segment }}",
                    "rightValue": "recipes"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Nonbrand Flow",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "e9624b23-70a7-4e4e-bd4c-72cf716d4fe7",
                    "operator": {
                      "name": "filter.operator.equals",
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.segment }}",
                    "rightValue": "nonbrand"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "notesInFlow": true,
      "typeVersion": 3.2
    },
    {
      "id": "6261fc22-cc1a-4421-a292-bde393b2a10b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -820,
        1760
      ],
      "parameters": {
        "width": 500,
        "height": 780,
        "content": "### This workflow helps SEO teams catch top movers in Google Search Console by comparing daily performance across keyword segments like brand, nonbrand, and content categories. \n\nInstead of serving as a routine check, it highlights the queries and pages with the biggest jumps or drops, making it ideal for spotting wins, losses, or unexpected shifts early.\n\n### How It Works\n1. Runs daily on a scheduled trigger (e.g. every morning).\n2. Pulls GSC data for the prior two days (e.g. yesterday vs. day before).\n3. Segments traffic by keyword type or URL pattern (e.g. brand, nonbrand, recipes).\n4. Calculates changes in clicks, impressions, CTR, and average position.\n5. Flags top movers with the biggest positive or negative deltas.\n6. Sends structured reports via Slack or email, grouped by segment and sorted by impact.\n\n### Setup Steps\n- Connect your Google Search Console account and optionally Gmail or Slack.\n- Swap in your own domain(s) and customize segmentation logic (e.g. brand terms, path filters).\n- By default, the workflow includes Slack alerts, but these can be easily switched to or combined with email, webhook, or other channels.\n- Full setup takes around 15\u201320 minutes with working GSC credentials.\n\n*Note: The \u201crecipes\u201d segment is included as an example of how to segment content. This can be changed to match blog, FAQ, product pages, or any other category.*"
      },
      "typeVersion": 1
    },
    {
      "id": "b621dc31-5815-4ab9-a2f7-8d6ffa67e9f3",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        2500
      ],
      "parameters": {
        "width": 230,
        "height": 140,
        "content": "### Current threshold is set to greater than 100 absolute delta clicks (i.e. positive or negative) and 30% absolute change."
      },
      "typeVersion": 1
    },
    {
      "id": "dda97dd6-d16e-4c61-ae02-7cda58acfc87",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        1900
      ],
      "parameters": {
        "width": 180,
        "height": 100,
        "content": "## Connect to GSC account"
      },
      "typeVersion": 1
    },
    {
      "id": "71506496-31fa-4322-8443-f877f3dba9e4",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1520,
        1720
      ],
      "parameters": {
        "height": 120,
        "content": "## Connect to Slack account or update to email/etc."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "788636aa-9891-4a6c-96e7-aa4f8833dfe3",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "priorDay",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "lastDay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Merge Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "label": {
      "main": [
        [
          {
            "node": "Flatten",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "label1": {
      "main": [
        [
          {
            "node": "Flatten1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Flatten": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "lastDay": {
      "main": [
        [
          {
            "node": "label1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Flatten1": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "priorDay": {
      "main": [
        [
          {
            "node": "label",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Days": {
      "main": [
        [
          {
            "node": "Tag KWs by Category",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Define Days": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Segment Switch": {
      "main": [
        [
          {
            "node": "Top Movers Filter",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Top Movers Filter1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Top Movers Filter2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Top Movers Filter3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger1": {
      "main": [
        [
          {
            "node": "Define Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top Movers Filter": {
      "main": [
        [
          {
            "node": "Top DoD Movers Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top Movers Filter1": {
      "main": [
        [
          {
            "node": "Top DoD Movers Alert1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top Movers Filter2": {
      "main": [
        [
          {
            "node": "Top DoD Movers Alert2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top Movers Filter3": {
      "main": [
        [
          {
            "node": "Top DoD Movers Alert3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tag KWs by Category": {
      "main": [
        [
          {
            "node": "Segment Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Top DoD Movers Alert": {
      "main": [
        []
      ]
    }
  }
}

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

Instead of serving as a routine check, it highlights the queries and pages with the biggest jumps or drops, making it ideal for spotting wins, losses, or unexpected shifts early. Runs daily on a scheduled trigger (e.g. every morning). Pulls GSC data for the prior two days (e.g.…

Source: https://n8n.io/workflows/6004/ — 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 workflow is an automated employee time tracking and reporting system that monitors weekly work hours via TMetric, then delivers personalized summaries directly to each team member on Slack. It co

HTTP Request, Item Lists, Data Table +1
Slack & Telegram

Import Productboard Notes Companies And Features Into Snowflake. Uses stickyNote, httpRequest, splitOut, snowflake. Scheduled trigger; 35 nodes.

HTTP Request, Snowflake, Slack
Slack & Telegram

Import Productboard Notes, Companies and Features into Snowflake. Uses stickyNote, httpRequest, splitOut, snowflake. Scheduled trigger; 35 nodes.

HTTP Request, Snowflake, Slack
Slack & Telegram

This workflow imports Productboard data into Snowflake, automating data extraction, mapping, and updates for features, companies, and notes. It supports scheduled weekly updates, data cleansing, and S

HTTP Request, Snowflake, Slack
Slack & Telegram

This workflow streamlines the entire inventory replenishment process by leveraging AI for demand forecasting and intelligent logic for supplier selection. It aggregates data from multiple sources—POS

HTTP Request, MySQL, Slack