{
  "id": "YDzSX1MoX82eMz4k",
  "name": "Detect content decay and alert via Slack and email",
  "tags": [
    {
      "id": "mHQntpbppFUpZPGm",
      "name": "template",
      "createdAt": "2026-02-17T08:30:26.885Z",
      "updatedAt": "2026-02-17T08:30:26.885Z"
    }
  ],
  "nodes": [
    {
      "id": "1fd97044-715a-4542-a99e-140e1d73ce73",
      "name": "Weekly Monday 8AM Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        320,
        320
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "34069535-dd52-4536-bbc8-f9abc5d7b9cc",
      "name": "Calculate Date Ranges",
      "type": "n8n-nodes-base.code",
      "position": [
        528,
        320
      ],
      "parameters": {
        "jsCode": "// Calculate date ranges\nconst now = new Date();\n\n// Recent period: last 7 days\nconst recentEnd = new Date(now);\nrecentEnd.setDate(recentEnd.getDate() - 3); // GSC data has 3-day delay\nconst recentStart = new Date(recentEnd);\nrecentStart.setDate(recentStart.getDate() - 7);\n\n// Previous period: 28 days before that\nconst prevEnd = new Date(recentStart);\nprevEnd.setDate(prevEnd.getDate() - 1);\nconst prevStart = new Date(prevEnd);\nprevStart.setDate(prevStart.getDate() - 28);\n\nconst fmt = (d) => d.toISOString().split('T')[0];\n\nreturn [{\n  json: {\n    recent_start: fmt(recentStart),\n    recent_end: fmt(recentEnd),\n    previous_start: fmt(prevStart),\n    previous_end: fmt(prevEnd)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "fdecf37e-0b0a-4542-9b18-6af9c37e894b",
      "name": "Fetch GSC Recent 7 Days",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        768,
        224
      ],
      "parameters": {
        "url": "https://www.googleapis.com/webmasters/v3/sites/{{ encodeURIComponent($env.GSC_SITE_URL) }}/searchAnalytics/query",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "jsonBody": "={\n  \"startDate\": \"{{ $json.recent_start }}\",\n  \"endDate\": \"{{ $json.recent_end }}\",\n  \"dimensions\": [\"page\"],\n  \"rowLimit\": 500,\n  \"startRow\": 0\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSearchConsoleOAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "7a9e78b0-dd0c-4fec-b8f2-6fffd93e56de",
      "name": "Fetch GSC Previous 28 Days",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        768,
        416
      ],
      "parameters": {
        "url": "https://www.googleapis.com/webmasters/v3/sites/{{ encodeURIComponent($env.GSC_SITE_URL) }}/searchAnalytics/query",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "jsonBody": "={\n  \"startDate\": \"{{ $json.previous_start }}\",\n  \"endDate\": \"{{ $json.previous_end }}\",\n  \"dimensions\": [\"page\"],\n  \"rowLimit\": 500,\n  \"startRow\": 0\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleSearchConsoleOAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "81576c4a-ae86-4edf-b2d6-fe218c9023e8",
      "name": "Compare Periods and Detect Decay",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        320
      ],
      "parameters": {
        "jsCode": "// Compare recent vs previous performance per page\nconst recentData = $('Fetch GSC Recent 7 Days').first().json;\nconst prevData = $('Fetch GSC Previous 28 Days').first().json;\n\nconst recentRows = recentData.rows || [];\nconst prevRows = prevData.rows || [];\n\n// Build lookup from previous period (normalize to weekly average)\nconst prevMap = {};\nfor (const row of prevRows) {\n  const page = row.keys[0];\n  prevMap[page] = {\n    clicks: row.clicks / 4,       // 28 days \u2192 weekly avg\n    impressions: row.impressions / 4,\n    ctr: row.ctr,\n    position: row.position\n  };\n}\n\nconst results = [];\n\nfor (const row of recentRows) {\n  const page = row.keys[0];\n  const prev = prevMap[page];\n\n  if (!prev) continue; // New page, skip\n  if (prev.clicks < 2) continue; // Too little traffic to matter\n\n  const clickChange = row.clicks - prev.clicks;\n  const clickChangePct = prev.clicks > 0 ? parseFloat(((clickChange / prev.clicks) * 100).toFixed(1)) : 0;\n  const impressionChange = row.impressions - prev.impressions;\n  const impressionChangePct = prev.impressions > 0 ? parseFloat(((impressionChange / prev.impressions) * 100).toFixed(1)) : 0;\n  const positionChange = parseFloat((row.position - prev.position).toFixed(1)); // positive = worse\n\n  // Determine decay severity\n  let signal = 'STABLE';\n  let severity = 'ok';\n\n  if (clickChangePct <= -50 || (positionChange >= 5 && clickChangePct <= -30)) {\n    signal = 'CRITICAL_DECAY';\n    severity = 'critical';\n  } else if (clickChangePct <= -30 || positionChange >= 3) {\n    signal = 'DECAYING';\n    severity = 'warning';\n  } else if (clickChangePct <= -15 || positionChange >= 1.5) {\n    signal = 'EARLY_DECAY';\n    severity = 'watch';\n  } else if (clickChangePct >= 20) {\n    signal = 'GROWING';\n    severity = 'good';\n  }\n\n  // Clean page path\n  let pagePath = page;\n  try {\n    pagePath = new URL(page).pathname;\n  } catch(e) {}\n\n  results.push({\n    json: {\n      page_url: page,\n      page_path: pagePath,\n      \n      clicks_now: row.clicks,\n      clicks_before: parseFloat(prev.clicks.toFixed(1)),\n      click_change: clickChange,\n      click_change_pct: clickChangePct,\n      \n      impressions_now: row.impressions,\n      impressions_before: parseFloat(prev.impressions.toFixed(1)),\n      impression_change_pct: impressionChangePct,\n      \n      position_now: parseFloat(row.position.toFixed(1)),\n      position_before: parseFloat(prev.position.toFixed(1)),\n      position_change: positionChange,\n      \n      ctr_now: parseFloat((row.ctr * 100).toFixed(2)),\n      ctr_before: parseFloat((prev.ctr * 100).toFixed(2)),\n      \n      signal: signal,\n      severity: severity,\n      \n      date: new Date().toISOString().split('T')[0]\n    }\n  });\n}\n\n// Sort by worst decay first\nresults.sort((a, b) => a.json.click_change_pct - b.json.click_change_pct);\n\nreturn results;"
      },
      "typeVersion": 2
    },
    {
      "id": "7a51c471-9f95-470c-b668-b5ea0aa46648",
      "name": "Log All Results to Decay Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1280,
        416
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $json.date }}",
            "signal": "={{ $json.signal }}",
            "ctr_now": "={{ $json.ctr_now }}",
            "page_path": "={{ $json.page_path }}",
            "clicks_now": "={{ $json.clicks_now }}",
            "position_now": "={{ $json.position_now }}",
            "clicks_before": "={{ $json.clicks_before }}",
            "impressions_now": "={{ $json.impressions_now }}",
            "position_before": "={{ $json.position_before }}",
            "position_change": "={{ $json.position_change }}",
            "click_change_pct": "={{ $json.click_change_pct }}",
            "impression_change_pct": "={{ $json.impression_change_pct }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Decay Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $env.DECAY_SHEET_URL }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "15898af0-2461-4f42-9804-6b02650ab69d",
      "name": "Filter Only Decaying Pages",
      "type": "n8n-nodes-base.filter",
      "position": [
        1280,
        224
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "is-critical",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.severity }}",
              "rightValue": "critical"
            },
            {
              "id": "is-warning",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.severity }}",
              "rightValue": "warning"
            },
            {
              "id": "is-watch",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.severity }}",
              "rightValue": "watch"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "51aa6fc9-3b2f-46d1-832a-aba1ef343635",
      "name": "Build Weekly Decay Report",
      "type": "n8n-nodes-base.code",
      "position": [
        1520,
        224
      ],
      "parameters": {
        "jsCode": "// Build the weekly decay report\nconst allPages = $('Compare Periods and Detect Decay').all().map(i => i.json);\nconst decaying = $input.all().map(i => i.json);\n\nconst critical = decaying.filter(p => p.severity === 'critical');\nconst warning = decaying.filter(p => p.severity === 'warning');\nconst watch = decaying.filter(p => p.severity === 'watch');\nconst stable = allPages.filter(p => p.severity === 'ok');\nconst growing = allPages.filter(p => p.severity === 'good');\n\nconst today = new Date().toISOString().split('T')[0];\n\n// Total clicks lost\nconst totalClicksLost = decaying\n  .filter(p => p.click_change < 0)\n  .reduce((sum, p) => sum + Math.abs(p.click_change), 0);\n\nlet report = `*CONTENT DECAY REPORT \u2014 ${today}*\\n`;\nreport += `Pages analyzed: ${allPages.length}\\n\\n`;\n\nreport += `Critical decay: ${critical.length}\\n`;\nreport += `Decaying: ${warning.length}\\n`;\nreport += `Early signs: ${watch.length}\\n`;\nreport += `Stable: ${stable.length}\\n`;\nreport += `Growing: ${growing.length}\\n`;\nreport += `\\n*Est. weekly clicks lost: ${Math.round(totalClicksLost)}*\\n`;\n\nif (critical.length > 0) {\n  report += `\\n\\n*CRITICAL \u2014 Act now:*\\n`;\n  for (const p of critical.slice(0, 10)) {\n    report += `\u2022 \\`${p.page_path}\\`\\n`;\n    report += `  Clicks: ${p.clicks_before} \u2192 ${p.clicks_now} (*${p.click_change_pct}%*)\\n`;\n    report += `  Position: ${p.position_before} \u2192 ${p.position_now} (${p.position_change > 0 ? '+' : ''}${p.position_change})\\n`;\n  }\n}\n\nif (warning.length > 0) {\n  report += `\\n*DECAYING \u2014 Update soon:*\\n`;\n  for (const p of warning.slice(0, 10)) {\n    report += `\u2022 \\`${p.page_path}\\` \u2014 clicks ${p.click_change_pct}%, pos ${p.position_change > 0 ? '+' : ''}${p.position_change}\\n`;\n  }\n}\n\nif (watch.length > 0) {\n  report += `\\n*EARLY SIGNS \u2014 Keep watching:*\\n`;\n  for (const p of watch.slice(0, 5)) {\n    report += `\u2022 \\`${p.page_path}\\` \u2014 clicks ${p.click_change_pct}%\\n`;\n  }\n}\n\nif (growing.length > 0) {\n  report += `\\n*TOP GROWING:*\\n`;\n  const topGrow = growing.sort((a, b) => b.click_change_pct - a.click_change_pct).slice(0, 3);\n  for (const p of topGrow) {\n    report += `\u2022 \\`${p.page_path}\\` \u2014 clicks +${p.click_change_pct}%\\n`;\n  }\n}\n\nreturn [{\n  json: {\n    report: report,\n    total_pages: allPages.length,\n    critical_count: critical.length,\n    warning_count: warning.length,\n    watch_count: watch.length,\n    clicks_lost: Math.round(totalClicksLost),\n    has_critical: critical.length > 0,\n    critical_pages: critical.slice(0, 10),\n    warning_pages: warning.slice(0, 10)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "48e028a0-fce2-4585-a9b4-ddef05f29639",
      "name": "Post Report to Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1760,
        112
      ],
      "parameters": {
        "text": "={{ $json.report }}",
        "otherOptions": {}
      },
      "typeVersion": 2.2
    },
    {
      "id": "aff9be9e-2e4f-4df1-ad5f-e32c1669476f",
      "name": "Email Weekly Report",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1760,
        320
      ],
      "parameters": {
        "options": {},
        "subject": "=Content Decay Report \u2014 {{ $json.critical_count }} critical, {{ $json.warning_count }} decaying | {{ $json.clicks_lost }} clicks lost"
      },
      "typeVersion": 2.1
    },
    {
      "id": "4cf96f14-e1e9-4164-aee7-1002121f0d90",
      "name": "Check If Any Critical Pages",
      "type": "n8n-nodes-base.filter",
      "position": [
        1760,
        512
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "has-critical",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.has_critical }}",
              "rightValue": "={{true}}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "52ef07b8-caa3-43a0-9898-efc5ff320bc1",
      "name": "Generate Fix Tasks for Critical Pages",
      "type": "n8n-nodes-base.code",
      "position": [
        1968,
        512
      ],
      "parameters": {
        "jsCode": "// Create individual tasks for critical decaying pages\nconst data = $input.first().json;\nconst tasks = [];\n\nfor (const page of data.critical_pages) {\n  let action = '';\n  \n  if (page.position_change >= 5) {\n    action = 'Major ranking drop. Check: lost backlinks, technical errors (404/redirect), or competitor new content. Run a backlink audit.';\n  } else if (page.impression_change_pct <= -40) {\n    action = 'Impressions tanking. Possible: Google algorithm change, keyword cannibalization, or index issues. Check Coverage report in GSC.';\n  } else if (page.ctr_now < page.ctr_before * 0.7) {\n    action = 'CTR dropped significantly. Update title tag and meta description. Check if SERP features (featured snippets, ads) pushed you down.';\n  } else {\n    action = 'Content likely outdated. Refresh with updated stats, new sections, better internal links. Check if search intent has shifted.';\n  }\n\n  tasks.push({\n    json: {\n      page_path: page.page_path,\n      page_url: page.page_url,\n      signal: page.signal,\n      click_change_pct: page.click_change_pct,\n      position_change: page.position_change,\n      recommended_action: action,\n      priority: 'HIGH',\n      created: new Date().toISOString().split('T')[0]\n    }\n  });\n}\n\nreturn tasks;"
      },
      "typeVersion": 2
    },
    {
      "id": "76f2b5b6-32c3-4261-8f6b-9183c61e38e1",
      "name": "Log Fix Tasks to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2192,
        512
      ],
      "parameters": {
        "columns": {
          "value": {
            "signal": "={{ $json.signal }}",
            "created": "={{ $json.created }}",
            "page_url": "={{ $json.page_url }}",
            "priority": "={{ $json.priority }}",
            "page_path": "={{ $json.page_path }}",
            "position_change": "={{ $json.position_change }}",
            "click_change_pct": "={{ $json.click_change_pct }}",
            "recommended_action": "={{ $json.recommended_action }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Fix Tasks"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $env.DECAY_SHEET_URL }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "dd580d9b-91f2-4e75-b5d3-5467860eb2e7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -704,
        -224
      ],
      "parameters": {
        "color": "#8D9C44",
        "width": 660,
        "height": 976,
        "content": "## Detect content decay and alert via Slack and email\n\nThis workflow automatically detects declining content performance by comparing your recent Google Search Console data against a historical baseline, then alerts you with actionable fix recommendations.\n\n## How it works\n1. **Runs every Monday at 8 AM** on a weekly schedule\n2. **Pulls last 7 days** of page-level data from Google Search Console (recent performance)\n3. **Pulls previous 28 days** as a baseline (normalized to weekly averages)\n4. **Compares per-page metrics** \u2014 clicks, impressions, position, and CTR\n5. **Classifies each page** into decay severity levels:\n   - **CRITICAL_DECAY** \u2014 clicks dropped 50%+ or position fell 5+ spots\n   - **DECAYING** \u2014 clicks dropped 30%+ or position fell 3+ spots\n   - **EARLY_DECAY** \u2014 clicks dropped 15%+ or position fell 1.5+ spots\n   - **STABLE** \u2014 no significant change\n   - **GROWING** \u2014 clicks up 20%+\n6. **Logs all results** to a Google Sheet for historical trend tracking\n7. **Sends a weekly report** via Slack and email with full breakdown\n8. **Auto-generates fix tasks** for critical pages with specific recommended actions\n\n## Setup steps\n1. Set **n8n environment variable** `GSC_SITE_URL` to your site (e.g., `https://yoursite.com`)\n2. Set **n8n environment variable** `DECAY_SHEET_URL` to your Google Sheet URL\n3. Create a Google Sheet with two tabs:\n   - `Decay Log` \u2014 headers: `date`, `page_path`, `signal`, `clicks_now`, `clicks_before`, `click_change_pct`, `position_now`, `position_before`, `position_change`, `impressions_now`, `impression_change_pct`, `ctr_now`\n   - `Fix Tasks` \u2014 headers: `created`, `priority`, `page_path`, `page_url`, `signal`, `click_change_pct`, `position_change`, `recommended_action`\n4. Connect **Google Search Console OAuth2** credentials\n5. Connect **Google Sheets OAuth2** credentials\n6. Connect **Slack OAuth2** credentials and set target channel\n7. Configure **SMTP / email** credentials and update recipient address\n\n## Customization\n- Adjust decay thresholds in the \"Compare Periods and Detect Decay\" node\n- Change schedule frequency (daily, bi-weekly, monthly)\n- Add more notification channels (Telegram, Discord, etc.)\n- Extend fix task logic with AI-powered content refresh suggestions"
      },
      "typeVersion": 1
    },
    {
      "id": "4ef309df-5f0e-44da-9136-6275543ae50e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        432,
        48
      ],
      "parameters": {
        "color": "#413A3A",
        "width": 328,
        "height": 164,
        "content": "## 1. Fetch GSC Data\nCalculates date ranges (recent 7 days vs. previous 28-day baseline) and fetches page-level performance from Google Search Console in parallel."
      },
      "typeVersion": 1
    },
    {
      "id": "6881902b-441f-45b6-84d2-030540de839f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1072,
        0
      ],
      "parameters": {
        "color": "#413A3A",
        "width": 332,
        "height": 164,
        "content": "## 2. Detect Decay\nCompares recent vs. baseline metrics per page. Classifies each page as CRITICAL_DECAY, DECAYING, EARLY_DECAY, STABLE, or GROWING based on click and position changes."
      },
      "typeVersion": 1
    },
    {
      "id": "89fa3787-df97-47dd-8dda-505d1c1d1416",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1680,
        -96
      ],
      "parameters": {
        "color": "#413A3A",
        "width": 276,
        "height": 180,
        "content": "## 3. Report and Alert\nBuilds a comprehensive weekly report with decay breakdown. Sends to Slack and email simultaneously. Pages with no decay are logged but not alerted."
      },
      "typeVersion": 1
    },
    {
      "id": "02088b0f-83f2-4b51-afa7-ac7345e04529",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1744,
        752
      ],
      "parameters": {
        "color": "#413A3A",
        "width": 332,
        "height": 180,
        "content": "## 4. Auto-Generate Fix Tasks\nFor critical pages, generates specific remediation tasks (backlink audit, content refresh, CTR optimization) and logs them to a separate Google Sheet tab."
      },
      "typeVersion": 1
    },
    {
      "id": "d1e6cb92-3abe-4f97-a433-4c80070e718b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        208,
        512
      ],
      "parameters": {
        "color": 3,
        "width": 480,
        "height": 140,
        "content": "\u26a0\ufe0f **Set environment variables** before activating:\n- `GSC_SITE_URL` \u2192 your verified site URL (e.g., `https://yoursite.com`)\n- `DECAY_SHEET_URL` \u2192 your Google Sheet URL for logging\n\nSee [n8n docs on environment variables](https://docs.n8n.io/hosting/configuration/environment-variables/)."
      },
      "typeVersion": 1
    },
    {
      "id": "8ab794a9-6860-45d1-80ff-bf6fba6ee2d0",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1984,
        304
      ],
      "parameters": {
        "color": 3,
        "width": 360,
        "height": 80,
        "content": "\u26a0\ufe0f **Update the email address** in this node to your own recipient address before activating."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "0b8ecf93-1ddd-42be-9caf-4acffd3eef84",
  "connections": {
    "Calculate Date Ranges": {
      "main": [
        [
          {
            "node": "Fetch GSC Recent 7 Days",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch GSC Previous 28 Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GSC Recent 7 Days": {
      "main": [
        [
          {
            "node": "Compare Periods and Detect Decay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Weekly Decay Report": {
      "main": [
        [
          {
            "node": "Check If Any Critical Pages",
            "type": "main",
            "index": 0
          },
          {
            "node": "Post Report to Slack",
            "type": "main",
            "index": 0
          },
          {
            "node": "Email Weekly Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Monday 8AM Trigger": {
      "main": [
        [
          {
            "node": "Calculate Date Ranges",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch GSC Previous 28 Days": {
      "main": [
        [
          {
            "node": "Compare Periods and Detect Decay",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Only Decaying Pages": {
      "main": [
        [
          {
            "node": "Build Weekly Decay Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check If Any Critical Pages": {
      "main": [
        [
          {
            "node": "Generate Fix Tasks for Critical Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Periods and Detect Decay": {
      "main": [
        [
          {
            "node": "Filter Only Decaying Pages",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log All Results to Decay Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Fix Tasks for Critical Pages": {
      "main": [
        [
          {
            "node": "Log Fix Tasks to Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}