This workflow corresponds to n8n.io template #7926 — we link there as the canonical source.
This workflow follows the Agent → Google Sheets 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 →
{
"id": "PieiJJOvbuPki3Mj",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "COPY Malicious URL",
"tags": [],
"nodes": [
{
"id": "b0c038b7-7362-45a3-a0ad-b1f1b5efc738",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
320,
-64
],
"parameters": {
"color": 3,
"width": 2348,
"height": 448,
"content": "Malicious URL Scanner Through Telegram"
},
"typeVersion": 1
},
{
"id": "4fe74461-614b-4fe1-a0ca-a06d003c056b",
"name": "VirusTotal HTTP Request",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
848,
208
],
"parameters": {
"": "",
"url": "https://www.virustotal.com/api/v3/urls",
"method": "POST",
"options": {},
"sendBody": false,
"sendQuery": true,
"curlImport": "",
"infoMessage": "",
"sendHeaders": false,
"specifyQuery": "keypair",
"authentication": "predefinedCredentialType",
"queryParameters": {
"parameters": [
{
"name": "url",
"value": "={{ $json.message.text }}"
}
]
},
"httpVariantWarning": "",
"nodeCredentialType": "virusTotalApi",
"provideSslCertificates": false
},
"credentials": {
"virusTotalApi": {
"name": "<your credential>"
}
},
"typeVersion": 4.2,
"extendsCredential": "virusTotalApi"
},
{
"id": "7438f4d5-4837-4dae-b92f-2075ca498cf9",
"name": "Send a text message",
"type": "n8n-nodes-base.telegram",
"position": [
2464,
-48
],
"parameters": {
"text": "={{ $json.output }}",
"chatId": "={{ $('Telegram Trigger').item.json.message.chat.id }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "8dfce473-9dc5-476e-99d2-c52c197f2f5d",
"name": "Telegram Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
368,
64
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "be71fedb-6aa7-4b77-ab99-3267ac8ec861",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
320,
-768
],
"parameters": {
"width": 464,
"height": 704,
"content": "Goal:\nThis workflow allows users to quickly analyze potentially malicious URLs received via text or email, directly from their mobile device using Telegram.\nWhen users don't have time to manually investigate links on a computer or search engine, they can simply paste the URL into the Telegram chat and receive a concise summary of the scan results\u2014powered by two open-source URL scanning services.\n\nDisclaimer:\nWhile this tool helps identify threats, it does not guarantee full protection. Use caution\u2014Telegram itself could be a potential point of compromise. Always follow safe browsing practices.\n\nWorkflow Nodes:\nTelegram Trigger \u2013 Listens for incoming messages with URLs.\n\nurlscan.io \u2013 Performs the first malicious URL scan.\n\nVirusTotal (HTTP Request) \u2013 Executes a second URL scan using VirusTotal.\n\nMerge Node \u2013 Combines the results from both scanners.\n\nAI Agent (ChatGPT with simple memory) \u2013 Analyzes the scan results and generates a readable summary.\n\nLimit Node \u2013 Ensures only one summary is sent per URL.\n\nTelegram Send Message Node \u2013 Sends the summary back to the user.\n\nGoogle Sheets (Logging) \u2013 Records scan results for auditing or historical reference.\n"
},
"typeVersion": 1
},
{
"id": "36f49fe2-ac55-4dde-8786-9c9611947173",
"name": "URL Logging",
"type": "n8n-nodes-base.googleSheets",
"position": [
2464,
176
],
"parameters": {
"columns": {
"value": {
"URL": "={{ $('Telegram Trigger').item.json.message.text }}",
"Report": "={{ $json.output }}",
"Date/Time": "={{ $now }}"
},
"schema": [
{
"id": "URL",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "URL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Report",
"type": "string",
"display": true,
"required": false,
"displayName": "Report",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Date/Time",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "Date/Time",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"URL"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1diuSW6dAgNu5XFH_sv1GF6TMlbm0jsokJmiuJzmSnUQ/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1diuSW6dAgNu5XFH_sv1GF6TMlbm0jsokJmiuJzmSnUQ",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1diuSW6dAgNu5XFH_sv1GF6TMlbm0jsokJmiuJzmSnUQ/edit?usp=drivesdk",
"cachedResultName": "URL Scanner"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "aefd6784-f72d-4a12-b2f9-5dca81481b8f",
"name": "Malicious URL Summary Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1712,
48
],
"parameters": {
"text": "=Role:\nYou are a cybersecurity assistant specializing in analyzing and summarizing URL scan reports. Use results from VirusTotal (always available) and urlscan.io (only if successful) to provide a professional, clear, and easy-to-understand summary.\n\nInstructions \u2013 Follow These Steps (Do Not Include in Final Summary):\n\n1.\tIdentify the scanned URL:\n{{ $('Telegram Trigger').item.json.message.text }}\n\n2. Check urlscan.io status (already provided by Code node):\n\u2981\tIf urlscan_status is \"success\" \u2192 include findings from urlscan_data alongside VirusTotal.\n\u2981\tIf urlscan_status is \"failed\" \u2192 rely only on VirusTotal and clearly state: \u201curlscan.io scan failed or was blocked.\u201d\n\n3. Assess threat level (based on VirusTotal):\nClassify as Harmless, Suspicious, or Malicious\n\u2981\tBase this on:\n\u2981\tThe number of engines that flagged the URL\n\u2981\tSeverity of detections from notable vendors (Kaspersky, Bitdefender, Sophos, etc.)\n\n4. Quantify detections:\n\u2981\tNumber of VirusTotal engines flagging the URL\n\u2981\tNotable antivirus vendors and what they reported\n\nProvide recommendation:\n\u2981\tUse plain, clear language for a general audience\n\u2981\tExamples: \u201cAppears safe,\u201d \u201cProceed with caution,\u201d \u201cAvoid this URL.\u201d\n\n\nOutput Format:\nTitle:\nSummary for {{ $('Telegram Trigger').item.json.message.text }} {{ $now }}\n\nBullet Points:\n\u2981\tThreat Level: [Harmless / Suspicious / Malicious]\n\u2981\tNumber of engines flagging the URL: [X engines]\n\u2981\tVirusTotal score: [Number or descriptive result]\n\nurlscan.io indicators:\n\u2981\tIf urlscan_status is \"success\" \u2192 summarize results from urlscan_data\n\u2981\tIf urlscan_status is \"failed\" \u2192 output exactly: \u201cScan failed or was blocked\u201d\n\n\u2981\tNotable detections: [List key AV engines if any]\n\u2981\tRecommendation: [Plain-language recommendation]\n\nFinal Summary (4\u20138 sentences):\n\u2981\tAlways provide a complete summary.\n\u2981\tIf urlscan.io succeeded \u2192 combine VirusTotal + urlscan.io results.\n\u2981\tIf urlscan.io failed \u2192 summarize VirusTotal results normally, then add one sentence noting the urlscan.io scan was blocked or failed.\n\u2981\tInclude: the URL, detection counts, notable antivirus vendors, and a clear recommendation.\n\nClose with this reminder:\nEven if a link appears safe, always exercise caution when clicking unknown URLs\u2014threats can evolve quickly.",
"options": {
"systemMessage": "You are a cybersecurity assistant designed to analyze and summarize URL scan results using data from VirusTotal and urlscan.io.\n\nYour role is to:\n\nProvide a concise, professional, and easy-to-understand summary of each scan.\n\nExtract key insights from the JSON responses of both services.\n\nNormalize and interpret data to assess whether the scanned URL is harmless, suspicious, or malicious.\n\nWrite in a tone that is accessible to users with basic technical literacy.\n\nAvoid raw JSON fields, API parameter names, or unnecessary technical jargon.\n\nFor each scan, your output should include:\n\nA bullet-point summary of the key findings.\n\nA short written summary (4\u20138 sentences) combining insights from both sources.\n\nA clear recommendation to help the user decide whether to avoid, review, or safely access the URL.\n\nAlways integrate results from both services into a unified, user-friendly report."
},
"promptType": "define"
},
"typeVersion": 2.2
},
{
"id": "4fae7e6b-8213-4aba-8dd2-9d3759a1e69a",
"name": "OpenAI Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1648,
224
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4",
"cachedResultName": "gpt-4"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "d2802345-d0e1-44b9-96b3-a8a84409dc51",
"name": "Malicious URL Memory",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
1888,
224
],
"parameters": {
"sessionKey": "summary",
"sessionIdType": "customKey"
},
"typeVersion": 1.3
},
{
"id": "66ea8113-1052-4b08-8ee4-af822a3d42c4",
"name": "Limit 1 Summary",
"type": "n8n-nodes-base.limit",
"position": [
2080,
48
],
"parameters": {},
"typeVersion": 1
},
{
"id": "df416f80-cc4d-4031-9e84-b929a262da0b",
"name": "urlscan Perform Scan",
"type": "n8n-nodes-base.urlScanIo",
"onError": "continueRegularOutput",
"position": [
848,
-32
],
"parameters": {
"url": "={{ $json.message.text }}",
"additionalFields": {}
},
"credentials": {
"urlScanIoApi": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "de9d28e5-6f58-48cd-af76-36c0c2160a4d",
"name": "Prepare Summary Data",
"type": "n8n-nodes-base.code",
"position": [
1472,
48
],
"parameters": {
"jsCode": "// Example Code node\n// Input: results from urlscan.io + VirusTotal + Telegram trigger\n\nconst items = $input.all();\n\n// Loop through items so we don\u2019t drop anything\nreturn items.map(item => {\n const urlscan = item.json.urlscan || {};\n const virustotal = item.json.virustotal || {};\n \n let summary = \"\";\n\n if (urlscan.message) {\n summary = `\u2705 urlscan.io result:\\n${JSON.stringify(urlscan)}\\n\\n\u2705 VirusTotal result:\\n${JSON.stringify(virustotal)}`;\n } else {\n summary = `\u26a0\ufe0f urlscan.io scan failed. Falling back to VirusTotal only:\\n${JSON.stringify(virustotal)}`;\n }\n\n // Preserve original fields (chatId, etc.)\n return {\n json: {\n ...item.json,\n summary, // add your summary field\n },\n binary: item.binary ?? undefined, // keep binary if exists\n };\n});\n\n"
},
"typeVersion": 2
},
{
"id": "056830ce-9c9e-4e4f-8d7c-51364596c6d7",
"name": "Merge Scans",
"type": "n8n-nodes-base.merge",
"position": [
1216,
48
],
"parameters": {},
"typeVersion": 3.2
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "49fe0c17-5447-4ec2-805a-8508d4463e5d",
"connections": {
"Merge Scans": {
"main": [
[
{
"node": "Prepare Summary Data",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Model": {
"ai_languageModel": [
[
{
"node": "Malicious URL Summary Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Limit 1 Summary": {
"main": [
[
{
"node": "Send a text message",
"type": "main",
"index": 0
},
{
"node": "URL Logging",
"type": "main",
"index": 0
}
]
]
},
"Telegram Trigger": {
"main": [
[
{
"node": "VirusTotal HTTP Request",
"type": "main",
"index": 0
},
{
"node": "urlscan Perform Scan",
"type": "main",
"index": 0
}
]
]
},
"Send a text message": {
"main": [
[]
]
},
"Malicious URL Memory": {
"ai_memory": [
[
{
"node": "Malicious URL Summary Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Prepare Summary Data": {
"main": [
[
{
"node": "Malicious URL Summary Agent",
"type": "main",
"index": 0
}
]
]
},
"urlscan Perform Scan": {
"main": [
[
{
"node": "Merge Scans",
"type": "main",
"index": 0
}
],
[]
]
},
"VirusTotal HTTP Request": {
"main": [
[
{
"node": "Merge Scans",
"type": "main",
"index": 1
}
]
]
},
"Malicious URL Summary Agent": {
"main": [
[
{
"node": "Limit 1 Summary",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
googleSheetsOAuth2ApiopenAiApitelegramApiurlScanIoApivirusTotalApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
The workflow is designed to scan submitted URLs using urlscan.io and VirusTotal, combine the results into a single structured summary, and send the report via Telegram.
Source: https://n8n.io/workflows/7926/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
BoomerBobBot.TP. Uses agent, telegramTrigger, telegram, memoryBufferWindow. Event-driven trigger; 95 nodes.
Generate AI viral videos with NanoBanana & VEO3, shared on socials via Blotato 2. Uses @blotato/n8n-nodes-blotato, googleSheets, lmChatOpenAi, toolThink. Event-driven trigger; 94 nodes.
Digital marketers, content creators, social media managers, and businesses who want to use AI marketing automation for YouTube Shorts without spending hours on production. This AI workflow helps anyon
This template is designed for marketers, content creators, and e-commerce brands who want to automate the creation of professional ad videos at scale. It’s ideal for teams looking to generate consiste
This automation is designed to help you generate AI-powered music tracks, cover art, and fully rendered music videos — all triggered from a simple Telegram chat and managed via Google Sheets.