This workflow corresponds to n8n.io template #5298 — we link there as the canonical source.
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 →
{
"name": "url-uptime-monitor",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 1
},
{}
]
}
},
"id": "1c49ff18-191b-4795-bdbe-2c80be834427",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
416,
560
],
"typeVersion": 1.2
},
{
"parameters": {
"fieldToSplitOut": "urls",
"options": {}
},
"id": "6f9a98c2-130d-49f6-9497-8e792f43263b",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
896,
464
],
"typeVersion": 1
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "{\n \"urls\": {\n \"URL 1\": \"https://cuongit.net\",\n \"URL 2\": \"https://tech36.net\",\n \"URL 3\": \"https://test.cuongit.net\", \n \"URL 4\": \"https://test1.cuongit.net\"\n }\n}",
"options": {}
},
"id": "3cf83123-9829-4dba-96fc-820b72f91970",
"name": "URLs",
"type": "n8n-nodes-base.set",
"position": [
672,
464
],
"typeVersion": 3.4
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "",
"mode": "url"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Monitorweb",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1audghXxGikfYkIMzGo-RANzCZCS2PablpGbr9uVQNBw/edit#gid=0"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"done": "=Done: {{ (Array.isArray($('Loop URLs').item.json.urls) ? $('Loop URLs').item.json.urls.join(', ') : $('Loop URLs').item.json.urls).toString().replace(/\\r?\\n/g, ' ') }}",
"time": "={{ new Date().toLocaleString('sv-SE', { timeZone: 'Asia/Ho_Chi_Minh' }) }}"
},
"matchingColumns": [
"time"
],
"schema": [
{
"id": "time",
"displayName": "time",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "error",
"displayName": "error",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": true
},
{
"id": "done",
"displayName": "done",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"id": "08cace4f-d4b9-4abe-b035-bc59ec260473",
"name": "Success",
"type": "n8n-nodes-base.googleSheets",
"position": [
1664,
624
],
"typeVersion": 4.6,
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "",
"mode": "url"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Monitorweb",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1audghXxGikfYkIMzGo-RANzCZCS2PablpGbr9uVQNBw/edit#gid=0"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"error": "=Error: {{ $json.urls }}",
"time": "={{ new Date().toLocaleString('vi-VN', { timeZone: 'Asia/Ho_Chi_Minh', hour12: false }) }}"
},
"matchingColumns": [],
"schema": [
{
"id": "time",
"displayName": "time",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "error",
"displayName": "error",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "done",
"displayName": "done",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"id": "6f910bbf-70bf-4002-8ade-fc28ed3ab50e",
"name": "Error",
"type": "n8n-nodes-base.googleSheets",
"position": [
1664,
848
],
"typeVersion": 4.6,
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"fieldsToSummarize": {
"values": [
{
"field": "done"
},
{
"field": "error"
}
]
},
"options": {}
},
"id": "12651162-043c-4e0a-8ef3-7bc8b7fdc04e",
"name": "Total",
"type": "n8n-nodes-base.summarize",
"position": [
1312,
384
],
"typeVersion": 1.1
},
{
"parameters": {},
"id": "3ae075a8-d4b5-4e38-a8cd-37cb1b3b2a3a",
"name": "Run trigger",
"type": "n8n-nodes-base.manualTrigger",
"position": [
416,
368
],
"typeVersion": 1
},
{
"parameters": {
"subject": "Webs Down",
"emailType": "text",
"message": "=We inform you that the following URLs are currently down:\n{{ ($('Aggregate Errors').first().json.urls || []).join('\\n') }}\n\nError: {{ $('Total').first().json.count_error }}\nTime: {{ new Date().toLocaleString('vi-VN', { timeZone: 'Asia/Ho_Chi_Minh', hour12: false }) }}\n",
"options": {}
},
"id": "3e06e308-db71-4b93-b36b-c4b4e25655f3",
"name": "Send a message",
"type": "n8n-nodes-base.gmail",
"position": [
2080,
512
],
"typeVersion": 2.1,
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// 1) Fetch ALL items emitted by the \"Loop URLs\" node\nconst items = $items('Loop URLs'); // the node name must match exactly\nconsole.log(items);\n\n// 2) Extract the \"error\" property and drop empty/whitespace-only values\nconst errorUrls = items\n .map(it => it.json.error)\n .filter(url => typeof url === 'string' && url.trim().length);\n\nif (errorUrls.length === 0) {\n throw new Error('No URLs were found in the \"error\" property.');\n}\n\n// Return one item per failed URL: { json: { url: \"<the url>\" } }\nreturn errorUrls.map(url => ({ json: { url } }));\n"
},
"id": "42d267ed-5d71-496c-a72e-d0727c56f86f",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
1520,
384
],
"typeVersion": 2
},
{
"parameters": {
"fieldToSplitOut": "url",
"options": {}
},
"id": "8032daea-87bf-4c60-954a-53617827b36d",
"name": "Split Out2",
"type": "n8n-nodes-base.splitOut",
"position": [
1696,
384
],
"typeVersion": 1
},
{
"parameters": {
"url": "={{ $json.urls }}",
"options": {}
},
"id": "fe2cdc77-ec82-4a70-88ae-881974d18533",
"name": "Request",
"type": "n8n-nodes-base.httpRequest",
"position": [
1296,
592
],
"typeVersion": 4.2,
"onError": "continueErrorOutput"
},
{
"parameters": {
"content": "## How it works (P1)\nBefore the loop, you enter the URLs to scan in the \"URLs\" stream, then start the trigger either manually or scheduled.",
"width": 260,
"color": 5
},
"id": "055e1a64-3c30-45e0-97a8-eb3aa7e9fcfa",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
688
],
"typeVersion": 1
},
{
"parameters": {
"content": "## How it works (P2)\nStart a loop for each URL entered, adding the status to a Google Sheet, then collect the status of each URL, filter out the crashes, and send an email, telegram with the crashes.",
"height": 180,
"width": 260
},
"id": "e3d65562-83a8-4b48-933f-f01215d893ba",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1920,
816
],
"typeVersion": 1
},
{
"parameters": {
"content": "### Enter URLs to scan here",
"height": 220,
"width": 180,
"color": 5
},
"id": "f1fd407b-548b-4f53-8781-43d9bd8e45ad",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
400
],
"typeVersion": 1
},
{
"parameters": {
"content": "### As a trigger you could also implement webhook or MCP",
"height": 480,
"width": 180,
"color": 5
},
"id": "5914dd63-1292-4ef4-b15f-d57d6dc2d8bc",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
368,
240
],
"typeVersion": 1
},
{
"parameters": {
"options": {}
},
"id": "0afdf309-8ad9-4e41-b323-9970fb0bf631",
"name": "Loop URLs",
"type": "n8n-nodes-base.splitInBatches",
"position": [
1088,
464
],
"typeVersion": 3
},
{
"parameters": {
"text": "=We inform you that the following URLs are currently down: {{$items(\"Split Out2\").map(it => it.json.url.replace(/^Error:\\s*/, '')).join('\\n')}}\n\nError: {{ $('Total').first().json.count_error }} \nTime: {{ new Date().toLocaleString('vi-VN', { timeZone: 'Asia/Ho_Chi_Minh', hour12: false }) }}",
"additionalFields": {}
},
"type": "n8n-nodes-base.telegram",
"typeVersion": 1.2,
"position": [
2064,
208
],
"id": "fc9cb246-8ec2-474a-b3e0-2304f6d957b3",
"name": "Send a text message",
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Aggregate Errors \u2014 preserve pairing so downstream nodes don't complain\nconst input = $input.all();\n\nconst urls = input\n .map(it => String(it.json?.url || '').replace(/^(Error|Fail):\\s*/, ''))\n .filter(Boolean);\n\n// If nothing came in, still return one item to avoid \"no items\" issues\nreturn [{\n json: {\n urls,\n count_error: urls.length\n },\n // Preserve pairing information for *all* input items\n pairedItem: input.map((_, idx) => ({ item: idx }))\n}];\n"
},
"id": "912a2064-16cc-4900-a023-0d7c840d76f4",
"name": "Aggregate Errors",
"type": "n8n-nodes-base.code",
"position": [
1872,
384
],
"typeVersion": 2
}
],
"connections": {
"Code": {
"main": [
[
{
"node": "Split Out2",
"type": "main",
"index": 0
}
]
]
},
"URLs": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Error": {
"main": [
[
{
"node": "Loop URLs",
"type": "main",
"index": 0
}
]
]
},
"Total": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Request": {
"main": [
[
{
"node": "Success",
"type": "main",
"index": 0
}
],
[
{
"node": "Error",
"type": "main",
"index": 0
}
]
]
},
"Success": {
"main": [
[
{
"node": "Loop URLs",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Loop URLs",
"type": "main",
"index": 0
}
]
]
},
"Split Out2": {
"main": [
[
{
"node": "Aggregate Errors",
"type": "main",
"index": 0
}
]
]
},
"Run trigger": {
"main": [
[
{
"node": "URLs",
"type": "main",
"index": 0
}
]
]
},
"Send a message": {
"main": [
[]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "URLs",
"type": "main",
"index": 0
}
]
]
},
"Loop URLs": {
"main": [
[
{
"node": "Total",
"type": "main",
"index": 0
}
],
[
{
"node": "Request",
"type": "main",
"index": 0
}
]
]
},
"Aggregate Errors": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
},
{
"node": "Send a text message",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {},
"versionId": "a57dca2e-09ec-4a0d-bea2-7b395bb7c745",
"meta": {
"templateId": "5298",
"templateCredsSetupCompleted": true
},
"id": "dTeyTnpDAIYf2r5K",
"tags": []
}
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.
gmailOAuth2googleSheetsOAuth2ApitelegramApi
About this workflow
url-uptime-monitor. Uses scheduleTrigger, splitOut, googleSheets, summarize. Scheduled trigger; 18 nodes.
Source: https://github.com/Cuongyd196/n8n-workflows/blob/main/workflows/devops/url-uptime-monitor/url-uptime-monitor.json — original creator credit. Request a take-down →