AutomationFlowsSlack & Telegram › Broken Link Monitor → Slack Alert

Broken Link Monitor → Slack Alert

13 - Broken Link Monitor → Slack Alert. Uses httpRequest, slack, googleSheets. Scheduled trigger; 7 nodes.

Cron / scheduled trigger★★★★☆ complexity7 nodesHTTP RequestSlackGoogle Sheets
Slack & Telegram Trigger: Cron / scheduled Nodes: 7 Complexity: ★★★★☆ Added:

This workflow follows the Google Sheets → 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
{
  "name": "13 - Broken Link Monitor \u2192 Slack Alert",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 * * * *"
            }
          ]
        }
      },
      "id": "node-schedule",
      "name": "Schedule - Every Hour",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        260,
        400
      ]
    },
    {
      "parameters": {
        "jsCode": "// Define URLs to monitor\n// Add your URLs here \u2014 can also be loaded from Google Sheets or a config file\nconst urlsToCheck = [\n  { url: 'https://yoursite.com', label: 'Homepage', critical: true },\n  { url: 'https://yoursite.com/pricing', label: 'Pricing Page', critical: true },\n  { url: 'https://yoursite.com/blog', label: 'Blog', critical: false },\n  { url: 'https://yoursite.com/api/health', label: 'API Health Check', critical: true },\n  { url: 'https://yoursite.com/contact', label: 'Contact Page', critical: false },\n  { url: 'https://yoursite.com/login', label: 'Login Page', critical: true },\n  { url: 'https://yoursite.com/docs', label: 'Documentation', critical: false },\n  { url: 'https://app.yoursite.com', label: 'App Homepage', critical: true }\n];\n\nreturn urlsToCheck.map(item => ({ json: item }));"
      },
      "id": "node-url-list",
      "name": "Code - URL List to Check",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        480,
        400
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ $json.url }}",
        "options": {
          "timeout": 10000,
          "allowUnauthorizedCerts": false,
          "response": {
            "response": {
              "responseFormat": "text",
              "fullResponse": true
            }
          },
          "redirect": {
            "redirect": {
              "followRedirects": true,
              "maxRedirects": 5
            }
          }
        }
      },
      "id": "node-http-check",
      "name": "HTTP Request - Check URL",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        700,
        400
      ],
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "const urlData = $('Code - URL List to Check').item.json;\nconst response = $input.first().json;\nconst error = $input.first().error;\n\nconst statusCode = response.statusCode || (error ? 0 : 200);\nconst responseTime = response.responseTime || 0;\n\nconst isBroken = statusCode === 0 || statusCode >= 400;\nconst isSlow = responseTime > 3000; // >3s is slow\n\nlet statusIcon = '\u2705';\nif (statusCode === 0) statusIcon = '\ud83d\udc80';\nelse if (statusCode >= 500) statusIcon = '\ud83d\udd34';\nelse if (statusCode >= 400) statusIcon = '\ud83d\udfe1';\nelse if (statusCode >= 300) statusIcon = '\ud83d\udfe0';\nelse if (isSlow) statusIcon = '\ud83d\udc22';\n\nreturn [{\n  json: {\n    url: urlData.url,\n    label: urlData.label,\n    critical: urlData.critical,\n    statusCode,\n    responseTime,\n    isBroken,\n    isSlow,\n    hasIssue: isBroken || (isSlow && urlData.critical),\n    statusIcon,\n    errorMessage: error?.message || '',\n    checkedAt: new Date().toISOString()\n  }\n}];"
      },
      "id": "node-evaluate",
      "name": "Code - Evaluate Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        920,
        400
      ]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $json.hasIssue }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ]
        }
      },
      "id": "node-if-broken",
      "name": "IF - Has Issue?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1140,
        400
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "C_DEVOPS_CHANNEL",
          "mode": "id"
        },
        "messageType": "block",
        "blocksUi": {
          "blocksValues": [
            {
              "type": "header",
              "text": {
                "type": "plain_text",
                "text": "{{ $json.statusCode >= 500 ? '\ud83d\udea8 CRITICAL' : $json.statusCode === 0 ? '\ud83d\udc80 UNREACHABLE' : '\u26a0\ufe0f WARNING' }} \u2014 Link Monitor Alert"
              }
            },
            {
              "type": "section",
              "fields": [
                {
                  "type": "mrkdwn",
                  "text": "*{{ $json.statusIcon }} {{ $json.label }}*\n`{{ $json.url }}`"
                },
                {
                  "type": "mrkdwn",
                  "text": "*Status Code:*\n{{ $json.statusCode === 0 ? 'TIMEOUT/UNREACHABLE' : $json.statusCode }}"
                },
                {
                  "type": "mrkdwn",
                  "text": "*Response Time:*\n{{ $json.responseTime }}ms"
                },
                {
                  "type": "mrkdwn",
                  "text": "*Critical Link:*\n{{ $json.critical ? 'YES \u26a0\ufe0f' : 'No' }}"
                }
              ]
            },
            {
              "type": "section",
              "text": {
                "type": "mrkdwn",
                "text": "{{ $json.errorMessage ? '*Error:* ' + $json.errorMessage : '*Issue:* ' + ($json.isBroken ? 'HTTP ' + $json.statusCode + ' response' : 'Slow response (>' + $json.responseTime + 'ms)') }}"
              }
            },
            {
              "type": "context",
              "elements": [
                {
                  "type": "mrkdwn",
                  "text": "Detected at {{ $json.checkedAt }} \u2022 n8n Link Monitor"
                }
              ]
            }
          ]
        }
      },
      "id": "node-slack-alert",
      "name": "Slack - Send Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1360,
        280
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_MONITOR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Monitor Log",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Timestamp": "={{ $json.checkedAt }}",
            "Label": "={{ $json.label }}",
            "URL": "={{ $json.url }}",
            "Status Code": "={{ $json.statusCode }}",
            "Response Time (ms)": "={{ $json.responseTime }}",
            "Is Broken": "={{ $json.isBroken ? 'YES' : 'NO' }}",
            "Is Slow": "={{ $json.isSlow ? 'YES' : 'NO' }}",
            "Critical": "={{ $json.critical ? 'YES' : 'NO' }}",
            "Error": "={{ $json.errorMessage }}"
          }
        },
        "options": {}
      },
      "id": "node-log",
      "name": "Google Sheets - Log Check Result",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        1360,
        520
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Schedule - Every Hour": {
      "main": [
        [
          {
            "node": "Code - URL List to Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - URL List to Check": {
      "main": [
        [
          {
            "node": "HTTP Request - Check URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request - Check URL": {
      "main": [
        [
          {
            "node": "Code - Evaluate Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - Evaluate Response": {
      "main": [
        [
          {
            "node": "IF - Has Issue?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF - Has Issue?": {
      "main": [
        [
          {
            "node": "Slack - Send Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Google Sheets - Log Check Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack - Send Alert": {
      "main": [
        [
          {
            "node": "Google Sheets - Log Check Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": [
    {
      "name": "monitoring"
    },
    {
      "name": "devops"
    },
    {
      "name": "alerts"
    }
  ],
  "meta": {
    "description": "Every hour, checks a configurable list of URLs via HTTP GET, evaluates status codes and response times, alerts Slack for broken/slow links, and logs every check result to Google Sheets for trending.",
    "prerequisites": [
      "Slack Bot Token with chat:write scope",
      "Google Sheets OAuth2 (optional, for logging)",
      "Update the URL list in Code node with your actual URLs",
      "Enable continueOnFail on HTTP node (already set) to handle timeouts gracefully"
    ],
    "testingScenario": {
      "happy_path": "All URLs return 200 \u2192 no Slack alert, all logged",
      "test_broken_link": "Add 'https://httpstat.us/404' to URL list \u2192 should trigger Slack alert",
      "test_timeout": "Add 'https://httpstat.us/200?sleep=15000' \u2192 triggers timeout/slow alert",
      "edge_cases": [
        "Redirect chains \u2192 followed up to 5 redirects",
        "SSL cert error \u2192 error message captured, shows as broken",
        "Rate limited (429) \u2192 shows as 429 warning, not critical",
        "Same URL alerting every hour \u2192 add dedup logic or Slack throttling"
      ]
    }
  }
}

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

13 - Broken Link Monitor → Slack Alert. Uses httpRequest, slack, googleSheets. Scheduled trigger; 7 nodes.

Source: https://github.com/satmakuru222/TheAIStackk/blob/main/n8n-workflows/13-broken-link-monitor-alert.json — 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 continuously monitors the Meta Ads Library for new creatives from a specific competitor pages, logs them into Google Sheets, and sends a concise Telegram notification with the number of

HTTP Request, Telegram, Google Sheets +1
Slack & Telegram

Enhance financial oversight with this automated n8n workflow. Triggered every 5 minutes, it fetches real-time bank transactions via an API, enriches and transforms the data, and applies smart logic to

HTTP Request, Email Send, Google Sheets +1
Slack & Telegram

This workflow automates competitive price intelligence using Bright Data's enterprise web scraping API. On a scheduled basis (default: daily at 9 AM), the system loops through configured competitor pr

HTTP Request, Google Sheets, Slack +1
Slack & Telegram

&gt; n8n, Binance API, Google Sheets, Slack, Telegram, Jira & Email

HTTP Request, Google Sheets, Slack +3
Slack & Telegram

SEO managers, content marketers, bloggers, and growth teams who want to automatically catch declining content performance before it's too late — without manually checking Google Search Console every w

HTTP Request, Google Sheets, Slack +1