{"workflow":{"id":13945,"name":"Track npm package downloads with Telegram commands and reports","views":23,"recentViews":0,"totalViews":23,"createdAt":"2026-03-08T20:29:22.391Z","description":"**Title**\n\nMonitor npm package downloads from Telegram with commands, weekly digests, milestone alerts,...\n\n**Short description**\n\nTrack npm package adoption directly from Telegram. This workflow provides on-demand download stats, automated weekly and monthly reports, growth trends, and milestone alerts using the public npm Downloads API.\n\n**What it does**\n\nThe workflow combines Telegram commands with scheduled reports to provide quick insights into package usage.\n\n**Commands**\n\n- `/downloads` - all-time totals, sorted highest first\n- `/weekly` - last 7 days per package\n- `/status` - weekly and all-time combined\n- `/trending` - this week vs last week\n- `/help` - available commands\n\n**Automated reports**\n\n- Weekly digest with package performance\n- Monthly summary comparing usage trends\n- Daily milestone checker that sends alerts when packages cross download thresholds\n\n**Smart defaults:**\n\n- Typo-tolerant command matching via Levenshtein distance\n- Slash optional, case insensitive\n- Auto-discovers packages from npm registry - new packages appear without code changes\n- Milestone check is silent on days with no crossings - zero noise","workflow":{"id":"3hWBSzxv0HLuvevU","meta":{"instanceId":"1a352c383ff1ed577e3f5bd4f450c0deba77f1e41bb95e8f52091f0c96d92af4","templateCredsSetupCompleted":true},"name":"NPM package tracker","tags":[],"nodes":[{"id":"d2168682-f0ed-4369-9c40-baee62aebab1","name":"Switch Command","type":"n8n-nodes-base.switch","position":[-16,1312],"parameters":{"rules":{"values":[{"outputKey":"downloads","conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"ceb74833-f6c6-490c-82d2-d3c368258c74","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.command }}","rightValue":"downloads"}]},"renameOutput":true},{"outputKey":"weekly","conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"3f4103fd-eb69-4b7a-b2c1-144c98b0bfa1","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.command }}","rightValue":"weekly"}]},"renameOutput":true},{"outputKey":"status","conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"1062ff98-6c0f-4edb-92ca-4574cee2462d","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.command }}","rightValue":"status"}]},"renameOutput":true},{"outputKey":"trending","conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"a366898b-55e2-4e64-bb23-d336bff8de39","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.command }}","rightValue":"trending"}]},"renameOutput":true},{"outputKey":"help","conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"149e6ff0-f9cc-4e54-b248-a3efd7678d8e","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.command }}","rightValue":"help"}]},"renameOutput":true},{"outputKey":"unknown","conditions":{"options":{"version":3,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"c345b813-8ce3-421f-a7d4-235049daf6b7","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.command }}","rightValue":"unknown"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.4},{"id":"d94f22e4-81e3-4f9a-af3d-001ad6c75868","name":"1st of Month 6PM","type":"n8n-nodes-base.scheduleTrigger","position":[-800,2800],"parameters":{"rule":{"interval":[{"field":"cronExpression","expression":"0 18 1 * *"}]}},"typeVersion":1.2},{"id":"fd700615-112e-4eb5-b951-6bb947102ca8","name":"Fetch Trending","type":"n8n-nodes-base.code","position":[512,1904],"parameters":{"jsCode":"// TRENDING - compares this week vs last week, shows growth rate\nconst NPM_USERNAME = 'monfortbrian';\nconst correctionNote = $input.first().json.wasCorrected ? `_✏️ Did you mean /${$input.first().json.correctedTo}? Showing results:_\\n\\n` : '';\n\nlet packages = [];\ntry {\n  const profile = await this.helpers.httpRequest({ method: 'GET', url: `https://registry.npmjs.org/-/v1/search?text=maintainer:${NPM_USERNAME}&size=50` });\n  packages = profile.objects.map(o => o.package.name);\n} catch(e) {\n  packages = ['n8n-nodes-csv-normalizer','n8n-nodes-mtn-momo','comprehensive-design-tokens','n8n-nodes-openmrs','n8n-nodes-dhis2','openmrs-sdk','n8n-nodes-rapidpro'];\n}\n\n// Get date ranges\nconst now = new Date();\nconst oneWeekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);\nconst twoWeeksAgo = new Date(now - 14 * 24 * 60 * 60 * 1000);\nconst fmt = d => d.toISOString().split('T')[0];\n\nconst thisWeekStart = fmt(oneWeekAgo);\nconst thisWeekEnd = fmt(now);\nconst lastWeekStart = fmt(twoWeeksAgo);\nconst lastWeekEnd = fmt(oneWeekAgo);\n\nconst results = [];\n\nfor (const pkg of packages) {\n  try {\n    const [thisWeek, lastWeek] = await Promise.all([\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/${thisWeekStart}:${thisWeekEnd}/${pkg}` }),\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/${lastWeekStart}:${lastWeekEnd}/${pkg}` })\n    ]);\n    const tw = thisWeek.downloads || 0;\n    const lw = lastWeek.downloads || 0;\n    const delta = tw - lw;\n    const pct = lw > 0 ? Math.round((delta / lw) * 100) : (tw > 0 ? 100 : 0);\n    const arrow = delta > 0 ? '🌱 ' : delta < 0 ? '⚠️' : '➖';\n    results.push({ pkg, tw, lw, delta, pct, arrow });\n  } catch (e) {\n    results.push({ pkg, tw: 0, lw: 0, delta: 0, pct: 0, arrow: '🆕' });\n  }\n}\n\n// Sort by absolute growth this week\nresults.sort((a, b) => b.tw - a.tw);\n\nconst winner = results[0];\nconst lines = results.map(r => {\n  const sign = r.delta >= 0 ? '+' : '';\n  return `  ${r.arrow} ${r.pkg}\\n     This week: ${r.tw} | Last week: ${r.lw}  |  ${sign}${r.delta} (${sign}${r.pct}%)`;\n});\n\nconst fmtDisplay = d => d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' });\n\nconst message = [\n  correctionNote + '🔥 *Trending Packages*',\n  `_${fmtDisplay(twoWeeksAgo)} vs ${fmtDisplay(oneWeekAgo)} - ${fmtDisplay(now)}_`,\n  '',\n  `🏆 *Top this week: ${winner.pkg}* (${winner.tw} downloads)`,\n  '',\n  lines.join('\\n'),\n  '',\n  '',\n  '_Sorted by downloads this week._'\n].join('\\n');\n\nreturn [{ json: { message, chatId: $input.first().json.chatId } }];"},"typeVersion":2},{"id":"e42a065d-3481-4142-9ab6-36e886c6f134","name":"Fetch Monthly Digest","type":"n8n-nodes-base.code","position":[-496,2800],"parameters":{"jsCode":"// MONTHLY DIGEST - 1st of every month 6PM GMT\nconst NPM_USERNAME = 'monfortbrian';\n\nlet packages = [];\ntry {\n  const profile = await this.helpers.httpRequest({ method: 'GET', url: `https://registry.npmjs.org/-/v1/search?text=maintainer:${NPM_USERNAME}&size=50` });\n  packages = profile.objects.map(o => o.package.name);\n} catch(e) {\n  packages = ['n8n-nodes-csv-normalizer','n8n-nodes-mtn-momo','comprehensive-design-tokens','n8n-nodes-openmrs','n8n-nodes-dhis2','openmrs-sdk','n8n-nodes-rapidpro'];\n}\n\nconst now = new Date();\nconst today = now.toISOString().split('T')[0];\n\n// Last month range\nconst lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0);\nconst lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);\n// Two months ago for comparison\nconst twoMonthsStart = new Date(now.getFullYear(), now.getMonth() - 2, 1);\nconst twoMonthsEnd = new Date(now.getFullYear(), now.getMonth() - 1, 0);\n\nconst fmt = d => d.toISOString().split('T')[0];\nconst monthName = d => d.toLocaleDateString('en-GB', { month: 'long', year: 'numeric' });\n\nconst results = [];\nlet monthTotal = 0;\nlet prevMonthTotal = 0;\nlet grandTotal = 0;\n\nfor (const pkg of packages) {\n  try {\n    const [thisMonth, prevMonth, allTime] = await Promise.all([\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/${fmt(lastMonthStart)}:${fmt(lastMonthEnd)}/${pkg}` }),\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/${fmt(twoMonthsStart)}:${fmt(twoMonthsEnd)}/${pkg}` }),\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/2020-01-01:${today}/${pkg}` })\n    ]);\n    const m = thisMonth.downloads || 0;\n    const pm = prevMonth.downloads || 0;\n    const a = allTime.downloads || 0;\n    monthTotal += m;\n    prevMonthTotal += pm;\n    grandTotal += a;\n    results.push({ pkg, m, pm, a });\n  } catch(e) {\n    results.push({ pkg, m: 0, pm: 0, a: 0 });\n  }\n}\n\nresults.sort((a, b) => b.m - a.m);\n\nconst delta = monthTotal - prevMonthTotal;\nconst sign = delta >= 0 ? '+' : '';\nconst arrow = delta > 0 ? '🌱' : delta < 0 ? '⚠️' : '➖';\nconst topPkg = results[0];\n\nconst message = [\n  `*Monthly Report - ${monthName(lastMonthStart)}*`,\n  '',\n  `${arrow} Month-over-month: *${sign}${delta}* downloads vs ${monthName(twoMonthsStart)}`,\n  '',\n  `🏆 Top package: *${topPkg.pkg}* (${topPkg.m} downloads)`,\n  '',\n  '📊 *This Month vs Last Month*',\n  results.map(r => {\n    const d = r.m - r.pm;\n    const s = d >= 0 ? '+' : '';\n    return `  • ${r.pkg}: ${r.m} _(${s}${d})_`;\n  }).join('\\n'),\n  `*Month Total: ${monthTotal.toLocaleString()}*`,\n  '',\n  '',\n  '📦 *All-Time Totals*',\n  results.map(r => `  • ${r.pkg}: ${r.a.toLocaleString()}`).join('\\n'),\n  `*Grand Total: ${grandTotal.toLocaleString()} downloads*`,\n  '',\n  '',\n  '🔗 [View on npm](https://www.npmjs.com/~monfortbrian)'\n].join('\\n');\n\nreturn [{ json: { message } }];"},"typeVersion":2},{"id":"79a50834-460e-42f7-a61e-d745fa12778f","name":"Check Milestones","type":"n8n-nodes-base.code","position":[-496,3040],"parameters":{"jsCode":"// MILESTONE CHECKER - runs daily at 9AM\n// Alerts when a package crosses 100, 500, 1000, 5000, 10000 downloads\nconst NPM_USERNAME = 'monfortbrian';\nconst MILESTONES = [100, 500, 1000, 5000, 10000, 50000, 100000];\n\nlet packages = [];\ntry {\n  const profile = await this.helpers.httpRequest({ method: 'GET', url: `https://registry.npmjs.org/-/v1/search?text=maintainer:${NPM_USERNAME}&size=50` });\n  packages = profile.objects.map(o => o.package.name);\n} catch(e) {\n  packages = ['n8n-nodes-csv-normalizer','n8n-nodes-mtn-momo','comprehensive-design-tokens','n8n-nodes-openmrs','n8n-nodes-dhis2','openmrs-sdk','n8n-nodes-rapidpro'];\n}\n\nconst today = new Date().toISOString().split('T')[0];\nconst yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString().split('T')[0];\n\nconst alerts = [];\n\nfor (const pkg of packages) {\n  try {\n    const [todayData, yesterdayData] = await Promise.all([\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/2020-01-01:${today}/${pkg}` }),\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/2020-01-01:${yesterday}/${pkg}` })\n    ]);\n    const current = todayData.downloads || 0;\n    const previous = yesterdayData.downloads || 0;\n\n    for (const milestone of MILESTONES) {\n      if (previous < milestone && current >= milestone) {\n        alerts.push({ pkg, milestone, current });\n      }\n    }\n  } catch(e) {}\n}\n\nif (alerts.length === 0) {\n  return [{ json: { hasAlerts: false, message: null } }];\n}\n\nconst lines = alerts.map(a => `🎉 *${a.pkg}* just crossed *${a.milestone.toLocaleString()} downloads!* (now at ${a.current.toLocaleString()})`);\n\nconst message = [\n  '🏆 *Milestone Alert!*',\n  '',\n  lines.join('\\n'),\n  '',\n  '_Keep shipping - the next milestone is closer than you think_'\n].join('\\n');\n\nreturn [{ json: { hasAlerts: true, message } }];"},"typeVersion":2},{"id":"bc57611c-85f0-49b4-ada2-afa92a5e29cd","name":"Has Milestones?","type":"n8n-nodes-base.if","position":[16,3040],"parameters":{"options":{},"conditions":{"conditions":[{"operator":{"type":"boolean","operation":"equals"},"leftValue":"={{ $json.hasAlerts }}","rightValue":true}]}},"typeVersion":2},{"id":"fed0f4e1-3749-42f2-9933-ab4c9e818bef","name":"Send Trending","type":"n8n-nodes-base.telegram","position":[848,1904],"webhookId":"48805bfc-0723-4918-9f56-0b5d39808891","parameters":{"text":"={{ $json.message }}","chatId":"={{ $json.chatId }}","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"695971b5-34d1-4cd8-99c1-8904be43463e","name":"Send Weekly Digest","type":"n8n-nodes-base.telegram","position":[864,2592],"webhookId":"dd7ed386-e17f-41ee-a28e-c358ed58dd28","parameters":{"text":"={{ $json.message }}","chatId":"123456789","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"ed776110-d887-4363-91ed-e990ad3e69b6","name":"Send Monthly Digest","type":"n8n-nodes-base.telegram","position":[864,2800],"webhookId":"3af10e29-27b8-4afc-9e8e-0fefdaaf7253","parameters":{"text":"={{ $json.message }}","chatId":"123456789","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"38150ac3-1e2f-4e81-9ec3-9cdb6e9e309b","name":"Send Milestone Alert","type":"n8n-nodes-base.telegram","position":[864,3024],"webhookId":"565010c5-bd97-4eac-8520-c5da401f2727","parameters":{"text":"={{ $json.message }}","chatId":"123456789","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"4eb0cc68-c920-45c2-ba62-983aa03d5778","name":"Send Downloads","type":"n8n-nodes-base.telegram","position":[848,1296],"webhookId":"8a0dde57-197e-4fab-a6b7-c3f1a5c898d6","parameters":{"text":"={{ $json.message }}","chatId":"={{ $json.chatId }}","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"b595746b-b9c0-4a59-93ab-6089efe37820","name":"Send Weekly","type":"n8n-nodes-base.telegram","position":[848,1488],"webhookId":"35c953b5-a443-4a5e-8edf-43f0303e3d44","parameters":{"text":"={{ $json.message }}","chatId":"={{ $json.chatId }}","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"27752c2f-469e-4a61-a3a4-8a17df0dcd6e","name":"Send Status","type":"n8n-nodes-base.telegram","position":[848,1696],"webhookId":"d4001271-7214-4efb-8153-0b782c60c8a6","parameters":{"text":"={{ $json.message }}","chatId":"={{ $json.chatId }}","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"27e41db2-4eab-4c43-b744-4ceec3bc13ab","name":"Send Help","type":"n8n-nodes-base.telegram","position":[864,2112],"webhookId":"fcb850e7-75c5-4ad6-a3ab-2cc72ed03d93","parameters":{"text":"={{ $json.message }}","chatId":"={{ $json.chatId }}","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"b34b3279-942a-43f5-a407-b48c6abc8069","name":"Send Unknown","type":"n8n-nodes-base.telegram","position":[864,2304],"webhookId":"ea500836-fb18-4fa9-b7d4-40bc0d9d5f78","parameters":{"text":"={{ $json.message }}","chatId":"={{ $json.chatId }}","additionalFields":{"parse_mode":"Markdown","appendAttribution":false}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.2},{"id":"7c81fc11-aba2-4628-9481-f6d6783305ed","name":"Fetch All-Time Downloads","type":"n8n-nodes-base.code","position":[512,1296],"parameters":{"jsCode":"const NPM_USERNAME = 'monfortbrian';\nconst correctionNote = $input.first().json.wasCorrected ? `_✏️ Did you mean /${$input.first().json.correctedTo}? Showing results:_\\n\\n` : '';\n\nlet packages = [];\ntry {\n  const profile = await this.helpers.httpRequest({ method: 'GET', url: `https://registry.npmjs.org/-/v1/search?text=maintainer:${NPM_USERNAME}&size=50` });\n  packages = profile.objects.map(o => o.package.name);\n} catch(e) {\n  packages = ['n8n-nodes-csv-normalizer','n8n-nodes-mtn-momo','comprehensive-design-tokens','n8n-nodes-openmrs','n8n-nodes-dhis2','openmrs-sdk','n8n-nodes-rapidpro'];\n}\n\nconst today = new Date().toISOString().split('T')[0];\nconst results = [];\nlet grandTotal = 0;\n\nfor (const pkg of packages) {\n  try {\n    const res = await this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/2020-01-01:${today}/${pkg}` });\n    const count = res.downloads || 0;\n    grandTotal += count;\n    results.push({ pkg, count });\n  } catch (e) {\n    results.push({ pkg, count: 0 });\n  }\n}\n\nresults.sort((a, b) => b.count - a.count);\nconst lines = results.map(r => `  • ${r.pkg}: ${r.count.toLocaleString()}`);\n\nconst message = [\n  correctionNote + '📦 *All-Time Downloads*',\n  '',\n  lines.join('\\n'),\n  '',\n  `*Grand Total: ${grandTotal.toLocaleString()} downloads*`\n].join('\\n');\n\nreturn [{ json: { message, chatId: $input.first().json.chatId } }];"},"typeVersion":2},{"id":"a1344ec4-4afb-44ea-9af1-da23f1874486","name":"Fetch Weekly Downloads","type":"n8n-nodes-base.code","position":[512,1488],"parameters":{"jsCode":"const NPM_USERNAME = 'monfortbrian';\nconst correctionNote = $input.first().json.wasCorrected ? `_✏️ Did you mean /${$input.first().json.correctedTo}? Showing results:_\\n\\n` : '';\n\nlet packages = [];\ntry {\n  const profile = await this.helpers.httpRequest({ method: 'GET', url: `https://registry.npmjs.org/-/v1/search?text=maintainer:${NPM_USERNAME}&size=50` });\n  packages = profile.objects.map(o => o.package.name);\n} catch(e) {\n  packages = ['n8n-nodes-csv-normalizer','n8n-nodes-mtn-momo','comprehensive-design-tokens','n8n-nodes-openmrs','n8n-nodes-dhis2','openmrs-sdk','n8n-nodes-rapidpro'];\n}\n\nconst results = [];\nlet weeklyTotal = 0;\n\nfor (const pkg of packages) {\n  try {\n    const res = await this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/last-week/${pkg}` });\n    const count = res.downloads || 0;\n    weeklyTotal += count;\n    results.push({ pkg, count });\n  } catch (e) {\n    results.push({ pkg, count: 0 });\n  }\n}\n\nresults.sort((a, b) => b.count - a.count);\nconst lines = results.map(r => `  • ${r.pkg}: ${r.count.toLocaleString()}`);\n\nconst now = new Date();\nconst weekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);\nconst fmt = d => d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' });\n\nconst message = [\n  correctionNote + `📊 *Weekly Downloads* (_${fmt(weekAgo)} - ${fmt(now)}_)`,\n  '',\n  lines.join('\\n'),\n  '',\n  `*This Week Total: ${weeklyTotal.toLocaleString()} downloads*`\n].join('\\n');\n\nreturn [{ json: { message, chatId: $input.first().json.chatId } }];"},"typeVersion":2},{"id":"3de20ce0-c41c-4c1e-9910-d714fbb04b21","name":"Fetch Status","type":"n8n-nodes-base.code","position":[512,1696],"parameters":{"jsCode":"const NPM_USERNAME = 'monfortbrian';\nconst correctionNote = $input.first().json.wasCorrected ? `_✏️ Did you mean /${$input.first().json.correctedTo}? Showing results:_\\n\\n` : '';\n\nlet packages = [];\ntry {\n  const profile = await this.helpers.httpRequest({ method: 'GET', url: `https://registry.npmjs.org/-/v1/search?text=maintainer:${NPM_USERNAME}&size=50` });\n  packages = profile.objects.map(o => o.package.name);\n} catch(e) {\n  packages = ['n8n-nodes-csv-normalizer','n8n-nodes-mtn-momo','comprehensive-design-tokens','n8n-nodes-openmrs','n8n-nodes-dhis2','openmrs-sdk','n8n-nodes-rapidpro'];\n}\n\nconst today = new Date().toISOString().split('T')[0];\nconst weeklyResults = [];\nconst allTimeResults = [];\nlet weeklyTotal = 0;\nlet grandTotal = 0;\n\nfor (const pkg of packages) {\n  try {\n    const [weekly, allTime] = await Promise.all([\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/last-week/${pkg}` }),\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/2020-01-01:${today}/${pkg}` })\n    ]);\n    const w = weekly.downloads || 0;\n    const a = allTime.downloads || 0;\n    weeklyTotal += w;\n    grandTotal += a;\n    weeklyResults.push({ pkg, count: w });\n    allTimeResults.push({ pkg, countW: w, countA: a });\n  } catch (e) {\n    weeklyResults.push({ pkg, count: 0 });\n    allTimeResults.push({ pkg, countW: 0, countA: 0 });\n  }\n}\n\nweeklyResults.sort((a, b) => b.count - a.count);\nallTimeResults.sort((a, b) => b.countA - a.countA);\n\nconst message = [\n  correctionNote + '*NPM Package Status*',\n  '',\n  '📊 *This Week*',\n  weeklyResults.map(r => `  • ${r.pkg}: ${r.count.toLocaleString()}`).join('\\n'),\n  `*Week Total: ${weeklyTotal.toLocaleString()}*`,\n  '',\n  '📦 *All-Time*',\n  allTimeResults.map(r => `  • ${r.pkg}: ${r.countA.toLocaleString()}`).join('\\n'),\n  `*Grand Total: ${grandTotal.toLocaleString()}*`\n].join('\\n');\n\nreturn [{ json: { message, chatId: $input.first().json.chatId } }];"},"typeVersion":2},{"id":"48634482-dc40-414a-942a-983c665a4e92","name":"Help Message","type":"n8n-nodes-base.code","position":[512,2112],"parameters":{"jsCode":"const chatId = $input.first().json.chatId;\n\nconst message = [\n  '*NPM Tracker - Commands*',\n  '',\n  '/downloads - All-time total per package',\n  '/weekly - Downloads this week',\n  '/status - Weekly + all-time combined',\n  '/trending - This week vs last week with growth %',\n  '/help - Show this message',\n  '',\n  '• _works with or without \"/\"_',\n  '• _typos auto-corrected_',\n  '• _packages sorted by downloads (highest first)_'\n].join('\\n');\n\nreturn [{ json: { message, chatId } }];"},"typeVersion":2},{"id":"4cf91307-35cc-45c2-9442-0c16737c0a9c","name":"Unknown Command","type":"n8n-nodes-base.code","position":[512,2304],"parameters":{"jsCode":"const chatId = $input.first().json.chatId;\nconst original = $input.first().json.original;\n\nconst message = [\n  `*\"${original}\"* - command not recognized`,\n  '',\n  'Available commands:',\n  '',\n  '/downloads',\n  '/weekly',\n  '/status',\n  '/trending',\n  '/help'\n].join('\\n');\n\nreturn [{ json: { message, chatId } }];"},"typeVersion":2},{"id":"40604584-62db-4d99-bb30-0cee6992bb77","name":"Parse Command","type":"n8n-nodes-base.code","position":[-512,1376],"parameters":{"jsCode":"// Fuzzy command matcher - handles typos, slash or no slash, any case\nfunction levenshtein(a, b) {\n  const m = a.length, n = b.length;\n  const dp = Array.from({length: m+1}, (_, i) => Array(n+1).fill(0).map((_, j) => i === 0 ? j : j === 0 ? i : 0));\n  for (let i = 1; i <= m; i++) {\n    for (let j = 1; j <= n; j++) {\n      dp[i][j] = a[i-1] === b[j-1] ? dp[i-1][j-1] : 1 + Math.min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]);\n    }\n  }\n  return dp[m][n];\n}\n\nconst raw = $input.first().json?.message?.text || '';\nconst chatId = $input.first().json?.message?.chat?.id;\nconst normalized = raw.trim().toLowerCase().replace(/^\\//, '');\n\nconst commands = ['downloads', 'weekly', 'status', 'trending', 'help'];\n\nlet best = null;\nlet bestScore = Infinity;\nfor (const cmd of commands) {\n  const score = levenshtein(normalized, cmd);\n  if (score < bestScore) { bestScore = score; best = cmd; }\n}\n\nconst matched = bestScore <= 4 ? best : 'unknown';\nconst wasCorrected = bestScore > 0 && bestScore <= 4 && normalized !== best;\n\nreturn [{ json: { command: matched, original: raw, chatId, wasCorrected, correctedTo: best } }];"},"typeVersion":2},{"id":"4b8fdde6-a8f1-4d17-a9c1-873145f3309d","name":"Every Friday 6PM","type":"n8n-nodes-base.scheduleTrigger","position":[-800,2592],"parameters":{"rule":{"interval":[{"field":"cronExpression","expression":"0 18 * * 5"}]}},"typeVersion":1.2},{"id":"f064321b-de5e-4e95-8429-13a7f74c83b3","name":"Milestone (daily check 9AM)","type":"n8n-nodes-base.scheduleTrigger","position":[-800,3040],"parameters":{"rule":{"interval":[{"field":"cronExpression","expression":"0 9 * * *"}]}},"typeVersion":1.2},{"id":"107d892a-8c7e-4f2c-8f16-a7801b1b5e77","name":"Fetch Weekly Digest","type":"n8n-nodes-base.code","position":[-496,2592],"parameters":{"jsCode":"// WEEKLY DIGEST - every Friday 6PM GMT\nconst NPM_USERNAME = 'monfortbrian';\n\nlet packages = [];\ntry {\n  const profile = await this.helpers.httpRequest({ method: 'GET', url: `https://registry.npmjs.org/-/v1/search?text=maintainer:${NPM_USERNAME}&size=50` });\n  packages = profile.objects.map(o => o.package.name);\n} catch(e) {\n  packages = ['n8n-nodes-csv-normalizer','n8n-nodes-mtn-momo','comprehensive-design-tokens','n8n-nodes-openmrs','n8n-nodes-dhis2','openmrs-sdk','n8n-nodes-rapidpro'];\n}\n\nconst now = new Date();\nconst oneWeekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);\nconst twoWeeksAgo = new Date(now - 14 * 24 * 60 * 60 * 1000);\nconst fmt = d => d.toISOString().split('T')[0];\nconst fmtDisplay = d => d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short' });\nconst today = fmt(now);\n\nconst weeklyResults = [];\nconst allTimeResults = [];\nlet weeklyTotal = 0;\nlet grandTotal = 0;\nlet prevWeekTotal = 0;\n\nfor (const pkg of packages) {\n  try {\n    const [weekly, prevWeekly, allTime] = await Promise.all([\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/${fmt(oneWeekAgo)}:${today}/${pkg}` }),\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/${fmt(twoWeeksAgo)}:${fmt(oneWeekAgo)}/${pkg}` }),\n      this.helpers.httpRequest({ method: 'GET', url: `https://api.npmjs.org/downloads/point/2020-01-01:${today}/${pkg}` })\n    ]);\n    const w = weekly.downloads || 0;\n    const pw = prevWeekly.downloads || 0;\n    const a = allTime.downloads || 0;\n    weeklyTotal += w;\n    prevWeekTotal += pw;\n    grandTotal += a;\n    weeklyResults.push({ pkg, w, pw });\n    allTimeResults.push({ pkg, a });\n  } catch(e) {\n    weeklyResults.push({ pkg, w: 0, pw: 0 });\n    allTimeResults.push({ pkg, a: 0 });\n  }\n}\n\nweeklyResults.sort((a, b) => b.w - a.w);\nallTimeResults.sort((a, b) => b.a - a.a);\n\nconst weekDelta = weeklyTotal - prevWeekTotal;\nconst weekSign = weekDelta >= 0 ? '+' : '';\nconst weekArrow = weekDelta > 0 ? '🌱' : weekDelta < 0 ? '⚠️' : '➖';\n\nconst topPackage = weeklyResults[0];\n\nconst message = [\n  `*Your Week on npm* (_${fmtDisplay(oneWeekAgo)} - ${fmtDisplay(now)}_)`,\n  '',\n  `${weekArrow} Week-over-week: *${weekSign}${weekDelta}* downloads vs last week`,\n  '',\n  `🏆 Top package: *${topPackage.pkg}* (${topPackage.w} this week)`,\n  '',\n  '📊 *This Week*',\n  weeklyResults.map(r => {\n    const d = r.w - r.pw;\n    const s = d >= 0 ? '+' : '';\n    return `  • ${r.pkg}: ${r.w} _(${s}${d} vs last week)_`;\n  }).join('\\n'),\n  `*Week Total: ${weeklyTotal.toLocaleString()}*`,\n  '',\n  '',\n  '📦 *All-Time*',\n  allTimeResults.map(r => `  • ${r.pkg}: ${r.a.toLocaleString()}`).join('\\n'),\n  `*Grand Total: ${grandTotal.toLocaleString()} downloads*`,\n  '',\n  '',\n  '🔗 [View on npm](https://www.npmjs.com/~monfortbrian)'\n].join('\\n');\n\nreturn [{ json: { message } }];"},"typeVersion":2},{"id":"ef764f5c-f774-4be2-ac28-5b53448dca26","name":"Telegram Trigger","type":"n8n-nodes-base.telegramTrigger","position":[-816,1376],"webhookId":"5618ad42-2cc6-4bfd-8a17-325f7a98812b","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"credential-id","name":"Telegram connection"}},"typeVersion":1.1},{"id":"c7e241a0-98ff-472b-8c15-3e463bbd922b","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[1184,1104],"parameters":{"width":480,"height":524,"content":"## Final Output\n![](https://res.cloudinary.com/dewqzljou/image/upload/v1773000261/NPM_package_tracker_-_demo_a59te9.jpg)"},"typeVersion":1},{"id":"853f6261-6b4f-4dba-98c3-e5f259c56b12","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[-1776,1344],"parameters":{"width":768,"height":1904,"content":"# NPM package tracker\n\nMonitor npm package downloads from Telegram with commands, weekly digests, and milestone alerts\n\n## Description\n\nThis template is designed for developers and teams who publish packages to npm and want simple visibility into package adoption.\n\nIt is particularly useful for:\n\n- Open-source maintainers managing multiple npm packages\n\n- Developer tool creators shipping libraries, plugins, or integrations\n\n- Engineering teams maintaining public SDKs or utilities\n\n- Agencies or startups distributing reusable packages\n\nInstead of manually checking npm statistics, this workflow delivers download insights automatically \nthrough Telegram.\n\n## What it does\n\nThe workflow combines Telegram commands with scheduled reports to provide quick insights into package usage.\n\n**Commands**\n\n- `/downloads` - all-time totals, sorted highest first\n- `/weekly` - last 7 days per package\n- `/status` - weekly and all-time combined\n- `/trending` - this week vs last week with delta and growth percentage\n- `/help` - available commands\n\n\n**Automated reports**\n\n- Weekly digest with package performance\n- Monthly summary comparing usage trends\n- Daily milestone checker that sends alerts when packages cross download thresholds\nThe workflow automatically discovers packages published under your npm username, so new packages appear in reports without any changes.\n\n\n**Smart defaults:**\n\n- Typo-tolerant command matching via Levenshtein distance\n- Slash optional, case insensitive\n- Auto-discovers packages from npm registry - new packages appear without code changes\n- Milestone check is silent on days with no crossings - zero noise\n\n## How it works\n\n1. A Telegram Trigger receives messages from the bot.\n2. A command parser identifies which command was sent.\n3. The workflow queries the npm Downloads API for package statistics.\n4. Results are formatted and sent back to Telegram.\n5. Scheduled triggers generate weekly and monthly reports and check milestone thresholds.\n\n## Set up steps\n\nSetup usually takes about **5–10 minutes**.\n\n1. Run n8n (Cloud or self-hosted)\n\n2. Create a Telegram bot via BotFather\n\n3. Import the workflow into n8n\n\n4. Add your Telegram bot credential\n\n5. Set your npm username in the Code nodes\n\n6. Activate the workflow"},"typeVersion":1},{"id":"5ed24a2d-3ba3-4a3a-ae7b-0366f20066f0","name":"Sticky Note10","type":"n8n-nodes-base.stickyNote","position":[400,1104],"parameters":{"color":7,"width":664,"height":2140,"content":"## What to change\n\n1. NPM_USERNAME in the Code nodes - set your npm username\n\n2. Telegram chatId in the digest and milestone nodes"},"typeVersion":1},{"id":"981950e9-cb2c-4f0a-a396-757a07cb6655","name":"Sticky Note11","type":"n8n-nodes-base.stickyNote","position":[-896,2352],"parameters":{"color":7,"width":584,"height":892,"content":"## What to change\n\n1. Cron schedules if you want different reporting times\n\n2. NPM_USERNAME in the Code nodes - set your npm username\n\n3. MILESTONES array to customize alert thresholds\n"},"typeVersion":1}],"active":true,"pinData":{},"settings":{"binaryMode":"separate","availableInMCP":false,"executionOrder":"v1"},"versionId":"5caf90e6-2ef6-4e96-87da-ecdd91ffd122","connections":{"Fetch Status":{"main":[[{"node":"Send Status","type":"main","index":0}]]},"Help Message":{"main":[[{"node":"Send Help","type":"main","index":0}]]},"Parse Command":{"main":[[{"node":"Switch Command","type":"main","index":0}]]},"Fetch Trending":{"main":[[{"node":"Send Trending","type":"main","index":0}]]},"Switch Command":{"main":[[{"node":"Fetch All-Time Downloads","type":"main","index":0}],[{"node":"Fetch Weekly Downloads","type":"main","index":0}],[{"node":"Fetch Status","type":"main","index":0}],[{"node":"Fetch Trending","type":"main","index":0}],[{"node":"Help Message","type":"main","index":0}],[{"node":"Unknown Command","type":"main","index":0}]]},"Has Milestones?":{"main":[[{"node":"Send Milestone Alert","type":"main","index":0}]]},"Unknown Command":{"main":[[{"node":"Send Unknown","type":"main","index":0}]]},"1st of Month 6PM":{"main":[[{"node":"Fetch Monthly Digest","type":"main","index":0}]]},"Check Milestones":{"main":[[{"node":"Has Milestones?","type":"main","index":0}]]},"Every Friday 6PM":{"main":[[{"node":"Fetch Weekly Digest","type":"main","index":0}]]},"Telegram Trigger":{"main":[[{"node":"Parse Command","type":"main","index":0}]]},"Fetch Weekly Digest":{"main":[[{"node":"Send Weekly Digest","type":"main","index":0}]]},"Fetch Monthly Digest":{"main":[[{"node":"Send Monthly Digest","type":"main","index":0}]]},"Fetch Weekly Downloads":{"main":[[{"node":"Send Weekly","type":"main","index":0}]]},"Fetch All-Time Downloads":{"main":[[{"node":"Send Downloads","type":"main","index":0}]]},"Milestone (daily check 9AM)":{"main":[[{"node":"Check Milestones","type":"main","index":0}]]}}},"lastUpdatedBy":1,"workflowInfo":{"nodeCount":29,"nodeTypes":{"n8n-nodes-base.if":{"count":1},"n8n-nodes-base.code":{"count":10},"n8n-nodes-base.switch":{"count":1},"n8n-nodes-base.telegram":{"count":9},"n8n-nodes-base.stickyNote":{"count":4},"n8n-nodes-base.scheduleTrigger":{"count":3},"n8n-nodes-base.telegramTrigger":{"count":1}}},"status":"published","readyToDemo":null,"user":{"name":"Monfort N. Brian | 宁俊","username":"monfortbrian","bio":"Product Designer <> Design Engineer","verified":false,"links":[""],"avatar":"https://gravatar.com/avatar/1c0badae99f892c30e45f4244fc8ea04317fd837258dfcb27ebe977d883849ab?r=pg&d=retro&size=200"},"nodes":[{"id":20,"icon":"fa:map-signs","name":"n8n-nodes-base.if","codex":{"data":{"alias":["Router","Filter","Condition","Logic","Boolean","Branch"],"details":"The IF node can be used to implement binary conditional logic in your workflow. You can set up one-to-many conditions to evaluate each item of data being inputted into the node. That data will either evaluate to TRUE or FALSE and route out of the node accordingly.\n\nThis node has multiple types of conditions: Bool, String, Number, and Date & Time.","resources":{"generic":[{"url":"https://n8n.io/blog/learn-to-automate-your-factorys-incident-reporting-a-step-by-step-guide/","icon":"🏭","label":"Learn to Automate Your Factory's Incident Reporting: A Step by Step Guide"},{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/create-a-toxic-language-detector-for-telegram/","icon":"🤬","label":"Create a toxic language detector for Telegram in 4 step"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/how-to-build-a-low-code-self-hosted-url-shortener/","icon":"🔗","label":"How to build a low-code, self-hosted URL shortener in 3 steps"},{"url":"https://n8n.io/blog/automate-your-data-processing-pipeline-in-9-steps-with-n8n/","icon":"⚙️","label":"Automate your data processing pipeline in 9 steps"},{"url":"https://n8n.io/blog/how-to-get-started-with-crm-automation-and-no-code-workflow-ideas/","icon":"👥","label":"How to get started with CRM automation (with 3 no-code workflow ideas"},{"url":"https://n8n.io/blog/5-tasks-you-can-automate-with-notion-api/","icon":"⚡️","label":"5 tasks you can automate with the new Notion API "},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/automation-for-maintainers-of-open-source-projects/","icon":"🏷️","label":"How to automatically manage contributions to open-source projects"},{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/","icon":"🤖","label":"5 workflow automations for Mattermost that we love at n8n"},{"url":"https://n8n.io/blog/why-this-product-manager-loves-workflow-automation-with-n8n/","icon":"🧠","label":"Why this Product Manager loves workflow automation with n8n"},{"url":"https://n8n.io/blog/sending-automated-congratulations-with-google-sheets-twilio-and-n8n/","icon":"🙌","label":"Sending Automated Congratulations with Google Sheets, Twilio, and n8n "},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/benefits-of-automation-and-n8n-an-interview-with-hubspots-hugh-durkin/","icon":"🎖","label":"Benefits of automation and n8n: An interview with HubSpot's Hugh Durkin"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.if/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Flow"]}}},"group":"[\"transform\"]","defaults":{"name":"If","color":"#408000"},"iconData":{"icon":"map-signs","type":"icon"},"displayName":"If","typeVersion":2,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":49,"icon":"file:telegram.svg","name":"n8n-nodes-base.telegram","codex":{"data":{"alias":["human","form","wait","hitl","approval"],"resources":{"generic":[{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/create-a-toxic-language-detector-for-telegram/","icon":"🤬","label":"Create a toxic language detector for Telegram in 4 step"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/world-poetry-day-workflow/","icon":"📜","label":"Celebrating World Poetry Day with a daily poem in Telegram"},{"url":"https://n8n.io/blog/using-automation-to-boost-productivity-in-the-workplace/","icon":"💪","label":"Using Automation to Boost Productivity in the Workplace"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/creating-scheduled-text-affirmations-with-n8n/","icon":"🤟","label":"Creating scheduled text affirmations with n8n"},{"url":"https://n8n.io/blog/creating-telegram-bots-with-n8n-a-no-code-platform/","icon":"💬","label":"Creating Telegram Bots with n8n, a No-Code Platform"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.telegram/"}],"credentialDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/credentials/telegram/"}]},"categories":["Communication","HITL"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"HITL":["Human in the Loop"]}}},"group":"[\"output\"]","defaults":{"name":"Telegram"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiB2aWV3Qm94PSIwIDAgNjYgNjYiPjx1c2UgeGxpbms6aHJlZj0iI2EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9ImEiIG92ZXJmbG93PSJ2aXNpYmxlIj48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0ibm9uZSI+PHBhdGggZmlsbD0iIzM3YWVlMiIgZD0iTTAgMzJjMCAxNy42NzMgMTQuMzI3IDMyIDMyIDMyczMyLTE0LjMyNyAzMi0zMlM0OS42NzMgMCAzMiAwIDAgMTQuMzI3IDAgMzIiLz48cGF0aCBmaWxsPSIjYzhkYWVhIiBkPSJtMjEuNjYxIDM0LjMzOCAzLjc5NyAxMC41MDhzLjQ3NS45ODMuOTgzLjk4MyA4LjA2OC03Ljg2NCA4LjA2OC03Ljg2NGw4LjQwNy0xNi4yMzctMjEuMTE5IDkuODk4eiIvPjxwYXRoIGZpbGw9IiNhOWM2ZDgiIGQ9Im0yNi42OTUgMzcuMDM0LS43MjkgNy43NDZzLS4zMDUgMi4zNzMgMi4wNjggMGw0LjY0NC00LjIwMyIvPjxwYXRoIGQ9Im0yMS43MyAzNC43MTItNy44MDktMi41NDVzLS45MzItLjM3OC0uNjMzLTEuMjM3Yy4wNjItLjE3Ny4xODYtLjMyOC41NTktLjU4OCAxLjczMS0xLjIwNiAzMi4wMjgtMTIuMDk2IDMyLjAyOC0xMi4wOTZzLjg1Ni0uMjg4IDEuMzYxLS4wOTdjLjIzMS4wODguMzc4LjE4Ny41MDMuNTQ4LjA0NS4xMzIuMDcxLjQxMS4wNjguNjg5LS4wMDMuMjAxLS4wMjcuMzg2LS4wNDUuNjc4LS4xODQgMi45NzgtNS43MDYgMjUuMTk4LTUuNzA2IDI1LjE5OHMtLjMzIDEuMy0xLjUxNCAxLjM0NWMtLjQzMi4wMTYtLjk1Ni0uMDcxLTEuNTgyLS42MS0yLjMyMy0xLjk5OC0xMC4zNTItNy4zOTQtMTIuMTI2LTguNThhLjM0LjM0IDAgMCAxLS4xNDYtLjIzOWMtLjAyNS0uMTI1LjEwOC0uMjguMTA4LS4yOHMxMy45OC0xMi40MjcgMTQuMzUyLTEzLjczMWMuMDI5LS4xMDEtLjA3OS0uMTUxLS4yMjYtLjEwNy0uOTI5LjM0Mi0xNy4wMjUgMTAuNTA2LTE4LjgwMSAxMS42MjktLjEwNC4wNjYtLjM5NS4wMjMtLjM5NS4wMjMiLz48L2c+PC9zeW1ib2w+PC9zdmc+"},"displayName":"Telegram","typeVersion":1,"nodeCategories":[{"id":6,"name":"Communication"},{"id":28,"name":"HITL"}]},{"id":50,"icon":"file:telegram.svg","name":"n8n-nodes-base.telegramTrigger","codex":{"data":{"resources":{"generic":[{"url":"https://n8n.io/blog/create-a-toxic-language-detector-for-telegram/","icon":"🤬","label":"Create a toxic language detector for Telegram in 4 step"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/creating-telegram-bots-with-n8n-a-no-code-platform/","icon":"💬","label":"Creating Telegram Bots with n8n, a No-Code Platform"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.telegramtrigger/"}],"credentialDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/credentials/telegram/"}]},"categories":["Communication"],"nodeVersion":"1.0","codexVersion":"1.0"}},"group":"[\"trigger\"]","defaults":{"name":"Telegram Trigger"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBmaWxsPSIjZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiB2aWV3Qm94PSIwIDAgNjYgNjYiPjx1c2UgeGxpbms6aHJlZj0iI2EiIHg9Ii41IiB5PSIuNSIvPjxzeW1ib2wgaWQ9ImEiIG92ZXJmbG93PSJ2aXNpYmxlIj48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0ibm9uZSI+PHBhdGggZmlsbD0iIzM3YWVlMiIgZD0iTTAgMzJjMCAxNy42NzMgMTQuMzI3IDMyIDMyIDMyczMyLTE0LjMyNyAzMi0zMlM0OS42NzMgMCAzMiAwIDAgMTQuMzI3IDAgMzIiLz48cGF0aCBmaWxsPSIjYzhkYWVhIiBkPSJtMjEuNjYxIDM0LjMzOCAzLjc5NyAxMC41MDhzLjQ3NS45ODMuOTgzLjk4MyA4LjA2OC03Ljg2NCA4LjA2OC03Ljg2NGw4LjQwNy0xNi4yMzctMjEuMTE5IDkuODk4eiIvPjxwYXRoIGZpbGw9IiNhOWM2ZDgiIGQ9Im0yNi42OTUgMzcuMDM0LS43MjkgNy43NDZzLS4zMDUgMi4zNzMgMi4wNjggMGw0LjY0NC00LjIwMyIvPjxwYXRoIGQ9Im0yMS43MyAzNC43MTItNy44MDktMi41NDVzLS45MzItLjM3OC0uNjMzLTEuMjM3Yy4wNjItLjE3Ny4xODYtLjMyOC41NTktLjU4OCAxLjczMS0xLjIwNiAzMi4wMjgtMTIuMDk2IDMyLjAyOC0xMi4wOTZzLjg1Ni0uMjg4IDEuMzYxLS4wOTdjLjIzMS4wODguMzc4LjE4Ny41MDMuNTQ4LjA0NS4xMzIuMDcxLjQxMS4wNjguNjg5LS4wMDMuMjAxLS4wMjcuMzg2LS4wNDUuNjc4LS4xODQgMi45NzgtNS43MDYgMjUuMTk4LTUuNzA2IDI1LjE5OHMtLjMzIDEuMy0xLjUxNCAxLjM0NWMtLjQzMi4wMTYtLjk1Ni0uMDcxLTEuNTgyLS42MS0yLjMyMy0xLjk5OC0xMC4zNTItNy4zOTQtMTIuMTI2LTguNThhLjM0LjM0IDAgMCAxLS4xNDYtLjIzOWMtLjAyNS0uMTI1LjEwOC0uMjguMTA4LS4yOHMxMy45OC0xMi40MjcgMTQuMzUyLTEzLjczMWMuMDI5LS4xMDEtLjA3OS0uMTUxLS4yMjYtLjEwNy0uOTI5LjM0Mi0xNy4wMjUgMTAuNTA2LTE4LjgwMSAxMS42MjktLjEwNC4wNjYtLjM5NS4wMjMtLjM5NS4wMjMiLz48L2c+PC9zeW1ib2w+PC9zdmc+"},"displayName":"Telegram Trigger","typeVersion":1,"nodeCategories":[{"id":6,"name":"Communication"}]},{"id":112,"icon":"fa:map-signs","name":"n8n-nodes-base.switch","codex":{"data":{"alias":["Router","If","Path","Filter","Condition","Logic","Branch","Case"],"resources":{"generic":[{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/how-to-get-started-with-crm-automation-and-no-code-workflow-ideas/","icon":"👥","label":"How to get started with CRM automation (with 3 no-code workflow ideas"},{"url":"https://n8n.io/blog/build-your-own-virtual-assistant-with-n8n-a-step-by-step-guide/","icon":"👦","label":"Build your own virtual assistant with n8n: A step by step guide"},{"url":"https://n8n.io/blog/automation-for-maintainers-of-open-source-projects/","icon":"🏷️","label":"How to automatically manage contributions to open-source projects"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.switch/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Flow"]}}},"group":"[\"transform\"]","defaults":{"name":"Switch","color":"#506000"},"iconData":{"icon":"map-signs","type":"icon"},"displayName":"Switch","typeVersion":3,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":565,"icon":"fa:sticky-note","name":"n8n-nodes-base.stickyNote","codex":{"data":{"alias":["Comments","Notes","Sticky"],"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers"]}}},"group":"[\"input\"]","defaults":{"name":"Sticky Note","color":"#FFD233"},"iconData":{"icon":"sticky-note","type":"icon"},"displayName":"Sticky Note","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":834,"icon":"file:code.svg","name":"n8n-nodes-base.code","codex":{"data":{"alias":["cpde","Javascript","JS","Python","Script","Custom Code","Function"],"details":"The Code node allows you to execute JavaScript in your workflow.","resources":{"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/"}]},"categories":["Development","Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers","Data Transformation"]}}},"group":"[\"transform\"]","defaults":{"name":"Code"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xMTcxXzQ0MSkiPgo8cGF0aCBkPSJNMTcwLjI4MyA0OEgxOTYuNUMyMDMuMTI3IDQ4IDIwOC41IDQyLjYyNzQgMjA4LjUgMzZWMTJDMjA4LjUgNS4zNzI1OCAyMDMuMTI3IDAgMTk2LjUgMEgxNzAuMjgzQzEyNi4xIDAgOTAuMjgzIDM1LjgxNzIgOTAuMjgzIDgwVjE3NkM5MC4yODMgMjA2LjkyOCA2NS4yMTA5IDIzMiAzNC4yODMgMjMySDIzQzE2LjM3MjYgMjMyIDExIDIzNy4zNzIgMTEgMjQ0VjI2OEMxMSAyNzQuNjI3IDE2LjM3MjQgMjgwIDIyLjk5OTYgMjgwTDM0LjI4MyAyODBDNjUuMjEwOSAyODAgOTAuMjgzIDMwNS4wNzIgOTAuMjgzIDMzNlY0NDBDOTAuMjgzIDQ3OS43NjQgMTIyLjUxOCA1MTIgMTYyLjI4MyA1MTJIMTk2LjVDMjAzLjEyNyA1MTIgMjA4LjUgNTA2LjYyNyAyMDguNSA1MDBWNDc2QzIwOC41IDQ2OS4zNzMgMjAzLjEyNyA0NjQgMTk2LjUgNDY0SDE2Mi4yODNDMTQ5LjAyOCA0NjQgMTM4LjI4MyA0NTMuMjU1IDEzOC4yODMgNDQwVjMzNkMxMzguMjgzIDMwOS4wMjIgMTI4LjAxMSAyODQuNDQzIDExMS4xNjQgMjY1Ljk2MUMxMDYuMTA5IDI2MC40MTYgMTA2LjEwOSAyNTEuNTg0IDExMS4xNjQgMjQ2LjAzOUMxMjguMDExIDIyNy41NTcgMTM4LjI4MyAyMDIuOTc4IDEzOC4yODMgMTc2VjgwQzEzOC4yODMgNjIuMzI2OSAxNTIuNjEgNDggMTcwLjI4MyA0OFoiIGZpbGw9IiNGRjk5MjIiLz4KPHBhdGggZD0iTTMwNSAzNkMzMDUgNDIuNjI3NCAzMTAuMzczIDQ4IDMxNyA0OEgzNDIuOTc5QzM2MC42NTIgNDggMzc0Ljk3OCA2Mi4zMjY5IDM3NC45NzggODBWMTc2QzM3NC45NzggMjAyLjk3OCAzODUuMjUxIDIyNy41NTcgNDAyLjA5OCAyNDYuMDM5QzQwNy4xNTMgMjUxLjU4NCA0MDcuMTUzIDI2MC40MTYgNDAyLjA5OCAyNjUuOTYxQzM4NS4yNTEgMjg0LjQ0MyAzNzQuOTc4IDMwOS4wMjIgMzc0Ljk3OCAzMzZWNDMyQzM3NC45NzggNDQ5LjY3MyAzNjAuNjUyIDQ2NCAzNDIuOTc5IDQ2NEgzMTdDMzEwLjM3MyA0NjQgMzA1IDQ2OS4zNzMgMzA1IDQ3NlY1MDBDMzA1IDUwNi42MjcgMzEwLjM3MyA1MTIgMzE3IDUxMkgzNDIuOTc5QzM4Ny4xNjEgNTEyIDQyMi45NzggNDc2LjE4MyA0MjIuOTc4IDQzMlYzMzZDNDIyLjk3OCAzMDUuMDcyIDQ0OC4wNTEgMjgwIDQ3OC45NzkgMjgwSDQ5MEM0OTYuNjI3IDI4MCA1MDIgMjc0LjYyOCA1MDIgMjY4VjI0NEM1MDIgMjM3LjM3MyA0OTYuNjI4IDIzMiA0OTAgMjMyTDQ3OC45NzkgMjMyQzQ0OC4wNTEgMjMyIDQyMi45NzggMjA2LjkyOCA0MjIuOTc4IDE3NlY4MEM0MjIuOTc4IDM1LjgxNzIgMzg3LjE2MSAwIDM0Mi45NzkgMEgzMTdDMzEwLjM3MyAwIDMwNSA1LjM3MjU4IDMwNSAxMlYzNloiIGZpbGw9IiNGRjk5MjIiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xMTcxXzQ0MSI+CjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo="},"displayName":"Code","typeVersion":2,"nodeCategories":[{"id":5,"name":"Development"},{"id":9,"name":"Core Nodes"}]},{"id":839,"icon":"fa:clock","name":"n8n-nodes-base.scheduleTrigger","codex":{"data":{"alias":["Time","Scheduler","Polling","Cron","Interval"],"resources":{"generic":[],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0"}},"group":"[\"trigger\",\"schedule\"]","defaults":{"name":"Schedule Trigger","color":"#31C49F"},"iconData":{"icon":"clock","type":"icon"},"displayName":"Schedule Trigger","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]}],"categories":[{"id":32,"name":"Market Research"},{"id":47,"name":"AI Chatbot"}],"image":[]}}