{ "name": "Uptime Kuma Alert Router", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "uptime-kuma", "responseMode": "onReceived", "options": {} }, "id": "webhook-1", "name": "Webhook - Uptime Kuma", "type": "n8n-nodes-base.webhook", "typeVersion": 1, "position": [250, 300], "webhookId": "uptime-kuma-alerts" }, { "parameters": { "conditions": { "string": [ { "value1": "={{ $json.body.monitor.name }}", "operation": "contains", "value2": "CRITICAL" } ] } }, "id": "filter-critical", "name": "Is CRITICAL?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [450, 200] }, { "parameters": { "conditions": { "string": [ { "value1": "={{ $json.body.monitor.name }}", "operation": "contains", "value2": "PUBLIC" } ] } }, "id": "filter-public", "name": "Is PUBLIC?", "type": "n8n-nodes-base.if", "typeVersion": 1, "position": [450, 400] }, { "parameters": { "functionCode": "// Parse Uptime Kuma webhook data\nconst data = $input.item.json.body;\nconst monitor = data.monitor;\nconst heartbeat = data.heartbeat;\n\n// Determine status emoji and color\nlet statusEmoji = '❓';\nlet statusText = 'UNKNOWN';\nlet color = '#808080';\n\nif (heartbeat.status === 1) {\n statusEmoji = '✅';\n statusText = 'UP';\n color = '#00ff00';\n} else if (heartbeat.status === 0) {\n statusEmoji = '❌';\n statusText = 'DOWN';\n color = '#ff0000';\n} else if (heartbeat.status === 2) {\n statusEmoji = '⏸️';\n statusText = 'PENDING';\n color = '#ffaa00';\n}\n\n// Extract priority from monitor name\nconst priorityMatch = monitor.name.match(/\\[(CRITICAL|PUBLIC|INTERNAL|METRICS|UTILITY)\\]/);\nconst priority = priorityMatch ? priorityMatch[1] : 'UNKNOWN';\n\n// Build formatted message\nconst message = {\n priority: priority,\n monitorName: monitor.name.replace(/\\[(CRITICAL|PUBLIC|INTERNAL|METRICS|UTILITY)\\]\\s*/, ''),\n fullName: monitor.name,\n status: statusText,\n statusEmoji: statusEmoji,\n statusColor: color,\n url: monitor.url || monitor.hostname || 'N/A',\n errorMessage: heartbeat.msg || 'No error message',\n timestamp: new Date(heartbeat.time).toLocaleString(),\n \n // Formatted messages for different channels\n slackMessage: `${statusEmoji} *${monitor.name}* is ${statusText}\\n` +\n `URL: ${monitor.url || monitor.hostname || 'N/A'}\\n` +\n `Error: ${heartbeat.msg || 'None'}\\n` +\n `Time: ${new Date(heartbeat.time).toLocaleString()}`,\n \n emailSubject: `[${priority}] ${monitor.name} is ${statusText}`,\n \n emailBody: `

${statusEmoji} Monitor Alert: ${statusText}

` +\n `

Monitor: ${monitor.name}

` +\n `

Status: ${statusText}

` +\n `

URL: ${monitor.url || monitor.hostname || 'N/A'}

` +\n `

Error: ${heartbeat.msg || 'None'}

` +\n `

Time: ${new Date(heartbeat.time).toLocaleString()}

` +\n `
` +\n `

Uptime Kuma Dashboard: http://10.0.10.26:3001

`\n};\n\nreturn { json: message };" }, "id": "format-data", "name": "Format Alert Data", "type": "n8n-nodes-base.function", "typeVersion": 1, "position": [650, 300] }, { "parameters": { "resource": "message", "text": "={{ $json.slackMessage }}", "additionalFields": { "attachments": [ { "color": "={{ $json.statusColor }}", "title": "{{ $json.fullName }}", "text": "{{ $json.errorMessage }}" } ] } }, "id": "slack-critical", "name": "Slack - CRITICAL Alert", "type": "n8n-nodes-base.slack", "typeVersion": 1, "position": [850, 100], "disabled": true, "credentials": { "slackApi": { "id": "1", "name": "Slack API" } }, "notes": "Enable and configure Slack credentials" }, { "parameters": { "text": "={{ $json.slackMessage }}", "additionalFields": {} }, "id": "discord-critical", "name": "Discord - CRITICAL Alert", "type": "n8n-nodes-base.discord", "typeVersion": 1, "position": [850, 200], "disabled": true, "notes": "Enable and configure Discord webhook" }, { "parameters": { "fromEmail": "uptime@nianticbooks.com", "toEmail": "fred@youremail.com", "subject": "={{ $json.emailSubject }}", "emailFormat": "html", "text": "={{ $json.emailBody }}", "options": {} }, "id": "email-critical", "name": "Email - CRITICAL Alert", "type": "n8n-nodes-base.emailSend", "typeVersion": 2, "position": [850, 300], "disabled": true, "notes": "Enable and configure SMTP settings" }, { "parameters": { "text": "={{ $json.slackMessage }}", "additionalFields": {} }, "id": "discord-public", "name": "Discord - PUBLIC Alert", "type": "n8n-nodes-base.discord", "typeVersion": 1, "position": [850, 400], "disabled": true, "notes": "Enable for public service alerts" }, { "parameters": { "functionCode": "// Log the alert for debugging\nconsole.log('Uptime Kuma Alert:', JSON.stringify($input.item.json, null, 2));\n\n// Store in database or just log\nreturn $input.all();" }, "id": "log-alert", "name": "Log Alert", "type": "n8n-nodes-base.function", "typeVersion": 1, "position": [850, 500], "notes": "Logs all alerts for debugging" } ], "connections": { "Webhook - Uptime Kuma": { "main": [ [ { "node": "Format Alert Data", "type": "main", "index": 0 } ] ] }, "Format Alert Data": { "main": [ [ { "node": "Is CRITICAL?", "type": "main", "index": 0 }, { "node": "Is PUBLIC?", "type": "main", "index": 0 }, { "node": "Log Alert", "type": "main", "index": 0 } ] ] }, "Is CRITICAL?": { "main": [ [ { "node": "Slack - CRITICAL Alert", "type": "main", "index": 0 }, { "node": "Discord - CRITICAL Alert", "type": "main", "index": 0 }, { "node": "Email - CRITICAL Alert", "type": "main", "index": 0 } ] ] }, "Is PUBLIC?": { "main": [ [ { "node": "Discord - PUBLIC Alert", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" }, "staticData": null, "tags": [], "triggerCount": 0, "updatedAt": "2025-12-29T00:00:00.000Z", "versionId": "1" }