This workflow corresponds to n8n.io template #14911 — we link there as the canonical source.
This workflow follows the Agent → Form Trigger 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": "tnfjdLbraIhUx2iC",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI-Powered NPM Package Intelligence Agent",
"tags": [],
"nodes": [
{
"id": "a5e2fb5c-4e69-4cd2-8b1e-4b0b7820e9ca",
"name": "Google Gemini Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
3744,
560
],
"parameters": {
"options": {
"temperature": 0
}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "eaafde3e-0e2c-42e4-824b-334ae92631f4",
"name": "Commit deatils",
"type": "n8n-nodes-base.set",
"position": [
2336,
368
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "855655e5-1041-4666-b5d0-fb20e2e0cf6e",
"name": "last_commit_date",
"type": "string",
"value": "={{ $json.commit.author.date }}"
},
{
"id": "4ba90cb3-db9a-434c-bd68-4aebbedbfebd",
"name": "commit_message",
"type": "string",
"value": "={{ $json.commit.message.slice(0, 100) }}"
},
{
"id": "aad68311-7ba7-48b7-9422-4d4c6e1c01f0",
"name": "commit_author",
"type": "string",
"value": "={{ $json.commit.author.name }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "05773347-85c0-4428-a616-2723b75ff8cb",
"name": "Github details",
"type": "n8n-nodes-base.set",
"position": [
2064,
512
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "855655e5-1041-4666-b5d0-fb20e2e0cf6e",
"name": "Github_Stars",
"type": "string",
"value": "={{ $json.stargazers_count }}"
},
{
"id": "4ba90cb3-db9a-434c-bd68-4aebbedbfebd",
"name": "open_issue_count",
"type": "string",
"value": "={{ $json.open_issues_count }}"
},
{
"id": "aad68311-7ba7-48b7-9422-4d4c6e1c01f0",
"name": "license",
"type": "string",
"value": "={{ $json.license.name }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a2d6dd78-9a35-4561-80c7-6c086ebfaf25",
"name": "/search in Firecrawl",
"type": "@mendable/n8n-nodes-firecrawl.firecrawlTool",
"position": [
4000,
608
],
"parameters": {
"query": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Query', ``, 'string') }}",
"resource": "MapSearch",
"operation": "search",
"requestOptions": {}
},
"credentials": {
"firecrawlApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "284c6dbf-f3c4-41de-a6eb-0687d954a41f",
"name": "/scrape in Firecrawl",
"type": "@mendable/n8n-nodes-firecrawl.firecrawlTool",
"position": [
4144,
480
],
"parameters": {
"url": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('URL', ``, 'string') }}",
"operation": "scrape",
"requestOptions": {}
},
"credentials": {
"firecrawlApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "732224f3-dbeb-4142-b837-c258663cd945",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-288,
-176
],
"parameters": {
"color": "#D7CCCC",
"width": 568,
"height": 1236,
"content": "## \ud83d\ude80 AI-Powered NPM Package Intelligence Agent (Powered by Firecrawl)\n\nThis workflow analyzes any npm package and delivers a data-driven recommendation using Firecrawl + APIs + AI reasoning.\n\n### \ud83d\udd25 Why Firecrawl is Important Here\n\nAt the core of this workflow is Firecrawl, which is used to:\n\n\u2022 Discover accurate npm package URLs dynamically\n\u2022 Identify the correct GitHub repository (even for tricky packages)\n\u2022 Enable AI agent to search & validate package context\n\u2022 Provide a fallback when direct API mapping is not straightforward\n\n\ud83d\udc49 Instead of hardcoding URLs, Firecrawl makes this workflow fully dynamic and scalable.\n\n### \ud83d\udd0d What it does\n\nThis workflow:\n\n\u2022 Accepts a package name via form\n\u2022 Uses Firecrawl Search to find npm + GitHub sources\n\u2022 Extracts clean URLs using logic layer\n\u2022 Fetches real-time data using APIs (GitHub + npm)\n\u2022 Calculates health metrics (activity, issue ratio)\n\u2022 Uses AI to generate insights + recommendations\n\u2022 Sends a clean Slack-ready report\n\n### \u2699\ufe0f How it works (High-level)\n\u2022 User submits package name\n\u2022 Firecrawl searches npm & GitHub (dynamic discovery layer)\n\u2022 Code node extracts clean, usable URLs\n\u2022 GitHub API \u2192 stars, issues, license\n\u2022 GitHub API \u2192 last commit activity\n\u2022 npm API \u2192 weekly downloads\n\u2022 Metrics calculated (health signals)\n\u2022 AI Agent analyzes + recommends\n\u2022 Slack message sent\n\n### \ud83e\udde0 Key Capabilities\n\n\u2022 Firecrawl-powered dynamic URL discovery (no hardcoding)\n\u2022 Real-time package evaluation using APIs\n\u2022 AI-powered reasoning (not just raw data)\n\u2022 Risk scoring (Low / Medium / High)\n\u2022 Handles invalid or missing packages gracefully\n\u2022 Produces structured + human-readable output\n\n### \u26a0\ufe0f Error Handling\n\n\u2022 Firecrawl ensures fallback discovery for URLs\n\u2022 API failures \u2192 handled using \"continue on fail\"\n\u2022 Missing package \u2192 fallback response with suggestions\n\u2022 Partial data \u2192 marked as \"unknown\"\n\u2022 URL detection failures \u2192 fallback to default npm URL\n\n### \ud83d\udce6 Requirements\n\n\u2022 Firecrawl API key \u2b50 (core component)\n\u2022 GitHub OAuth credential\n\u2022 Google Gemini API key\n\u2022 Slack credential (optional for output)\n\n### \ud83d\udca1 Example Use Cases\n\n\u2022 Package evaluation before production use\n\u2022 Comparing npm alternatives\n\u2022 Developer productivity tooling\n\u2022 Automated tech due diligence\n\n### \ud83c\udfaf Output\n\n\u2022 Structured JSON (for automation)\n\u2022 Slack-ready formatted report (for humans)"
},
"typeVersion": 1
},
{
"id": "bab82f8f-6ec1-48bc-bafd-b98a235bac5a",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
4304,
592
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"retryOnFail": true,
"typeVersion": 1
},
{
"id": "2daa940a-36f6-4700-85a9-eab67fa6db85",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
3856,
592
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini"
},
"options": {},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "94709f3b-7ea4-4dd5-9283-7474fcf14e76",
"name": "Enter Package Name",
"type": "n8n-nodes-base.formTrigger",
"position": [
400,
400
],
"parameters": {
"options": {},
"formTitle": "AI-Powered NPM Package Intelligence Agent (Powered by Firecrawl)",
"formFields": {
"values": [
{
"fieldLabel": "Package Name",
"requiredField": true
}
]
}
},
"typeVersion": 2.5
},
{
"id": "e5b67031-d900-4854-934a-bd01956ab081",
"name": "Normalize Input",
"type": "n8n-nodes-base.set",
"position": [
624,
400
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "ff05d934-2cac-45ef-8b91-fbff026dd2f2",
"name": "package_name",
"type": "string",
"value": "={{ $json['Package Name'] }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "c8c2d014-f728-467b-9412-f6f823cb0d1d",
"name": "Search NPM URL",
"type": "@mendable/n8n-nodes-firecrawl.firecrawl",
"position": [
848,
400
],
"parameters": {
"limit": 3,
"query": "={{ $json.package_name + \" site:npmjs.com/package\" }}",
"resource": "MapSearch",
"operation": "search",
"requestOptions": {}
},
"credentials": {
"firecrawlApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "f680931b-0d80-4296-b662-3060da5cf364",
"name": "Search GitHub Repo",
"type": "@mendable/n8n-nodes-firecrawl.firecrawl",
"position": [
1008,
592
],
"parameters": {
"limit": 3,
"query": "={{ $('Normalize Input').item.json.package_name + \" site:github.com\" }}",
"resource": "MapSearch",
"operation": "search",
"requestOptions": {}
},
"credentials": {
"firecrawlApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a53bc9a6-e5e4-4210-b822-002cbada124b",
"name": "Merge Search Results",
"type": "n8n-nodes-base.merge",
"position": [
1152,
352
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "bea816b4-7601-42d1-9494-b77e16ea8818",
"name": "Extract Clean URLs",
"type": "n8n-nodes-base.code",
"position": [
1520,
400
],
"parameters": {
"jsCode": "// \u2705 Get merged search results\nconst results = $json.data?.web || [];\n\n// \u2705 Get original package name safely\nconst package_name = $items(\"Normalize Input\")[0].json.package_name;\n\nlet npm_url = null;\nlet github_url = null;\n\n// \ud83d\udd01 Loop through search results\nfor (const r of results) {\n const raw = r.url || \"\";\n const url = raw.toLowerCase();\n\n // \ud83d\udeab Skip unwanted GitHub links\n if (\n url.includes(\"blob\") ||\n url.includes(\"issues\") ||\n url.includes(\"pull\") ||\n url.includes(\"commit\") ||\n url.includes(\"releases\")\n ) continue;\n\n // \u2705 STRICT npm match (very important)\n if (\n !npm_url &&\n url.includes(`npmjs.com/package/${package_name.toLowerCase()}`)\n ) {\n npm_url = raw;\n }\n\n // \u2705 GitHub repo detection (clean repo only)\n if (\n !github_url &&\n url.includes(\"github.com\") &&\n url.split(\"/\").length <= 5\n ) {\n github_url = raw;\n }\n}\n\n// \ud83d\udd01 Fallback npm (always safe)\nif (!npm_url && package_name) {\n npm_url = `https://www.npmjs.com/package/${package_name}`;\n}\n\n// \ud83c\udfaf Confidence scoring (bonus for judges)\nlet url_confidence = \"low\";\n\nif (npm_url && github_url) {\n url_confidence = \"high\";\n} else if (npm_url || github_url) {\n url_confidence = \"medium\";\n}\n\n// \ud83d\udce6 Final output\nreturn [\n {\n npm_url,\n github_url,\n url_confidence\n }\n];"
},
"typeVersion": 2
},
{
"id": "6e708352-21eb-49e4-9ef3-c31880b0e088",
"name": "Fetch GitHub Stats",
"type": "n8n-nodes-base.github",
"onError": "continueRegularOutput",
"position": [
1872,
448
],
"parameters": {
"owner": {
"__rl": true,
"mode": "name",
"value": "={{ $json.github_url.replace('https://github.com/', '').split('/')[0] }}"
},
"resource": "repository",
"operation": "get",
"repository": {
"__rl": true,
"mode": "name",
"value": "={{ $json.github_url.replace('https://github.com/', '').split('/')[1] }}"
},
"authentication": "oAuth2"
},
"credentials": {
"githubOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "3fbb1709-8258-4a87-a8b5-70b983e2db8d",
"name": "Fetch Last Commit",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
2160,
256
],
"parameters": {
"url": "={{\n (() => {\n const url = $('Extract Clean URLs').item.json.github_url || \"\";\n\n if (!url.includes(\"github.com\")) return null;\n\n const parts = url.replace(\"https://github.com/\", \"\").split(\"/\");\n\n if (parts.length < 2) return null;\n\n return `https://api.github.com/repos/${parts[0]}/${parts[1]}/commits?per_page=1`;\n })()\n}}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"typeVersion": 4.4
},
{
"id": "9fda051e-bf2b-4b40-8f82-1478fa2694f7",
"name": "Fetch NPM Downloads",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
2576,
288
],
"parameters": {
"url": "=https://api.npmjs.org/downloads/point/last-week/{{ $('Normalize Input').item.json.package_name }}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
},
"typeVersion": 4.4
},
{
"id": "82bd375f-cdbd-4bf1-8f60-cd010f6c2500",
"name": "Merge All Metrics",
"type": "n8n-nodes-base.merge",
"position": [
2848,
384
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition",
"numberInputs": 3
},
"typeVersion": 3.2
},
{
"id": "b5228e78-f6ef-4798-ba56-5e782b86e4b3",
"name": "Compute Health Metrics",
"type": "n8n-nodes-base.set",
"position": [
3088,
400
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "855655e5-1041-4666-b5d0-fb20e2e0cf6e",
"name": "issue_to_star_ratio",
"type": "string",
"value": "={{ $json.open_issue_count / $json.Github_Stars }}"
},
{
"id": "1db7b2c2-024f-4047-bfe4-48a3f102b254",
"name": "activity_status",
"type": "string",
"value": "={{ (new Date() - new Date($json.last_commit_date)) < 7 * 24 * 60 * 60 * 1000 ? \"active\" : \"stale\" }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8ad95726-f571-4897-a3de-850476bcad3a",
"name": "Check Package Valid",
"type": "n8n-nodes-base.if",
"position": [
3312,
400
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "b1c20669-b3a3-4d5a-bb0b-5663702185ea",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $('Github details').item.json.Github_Stars }}",
"rightValue": 0
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "857ea57a-8549-4071-8529-752e116f6f62",
"name": "Package Not Found Handler",
"type": "n8n-nodes-base.set",
"position": [
4064,
1232
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "04289d0e-19b2-49a2-8933-304dbe04d3bc",
"name": "Package not found",
"type": "object",
"value": "={\n \"package_info\": {\n \"name\": \"unknown\",\n \"corrected_name\": \"unknown\"\n },\n \"summary_block\": {\n \"description\": \"Package not found or data unavailable.\",\n \"summary\": \"The requested npm package could not be located or validated.\"\n },\n \"observed_facts\": [\n \"No matching package found on npm registry\",\n \"No GitHub repository could be resolved\",\n \"Search results did not return a reliable match\"\n ],\n \"inferred_judgment\": {\n \"maintenance_risk\": {\n \"level\": \"High\",\n \"reason\": \"Package does not exist or cannot be verified\"\n },\n \"adoption_risk\": {\n \"level\": \"High\",\n \"reason\": \"No usage or community signals available\"\n },\n \"breaking_change_risk\": {\n \"status\": \"Unknown\",\n \"reason\": \"No release or version history found\"\n }\n },\n \"risk\": {\n \"level\": \"High\",\n \"score\": 1,\n \"color\": \"red\",\n \"reason\": \"Package could not be validated from trusted sources\"\n },\n \"decision\": {\n \"recommendation\": \"Avoid\",\n \"confidence\": 0.95,\n \"reason\": \"Unverified or non-existent packages should not be used in production\"\n },\n \"alternatives\": [\n {\n \"name\": \"Search suggestion\",\n \"tradeoff\": \"User should verify correct package name\",\n \"use_case\": \"Try similar or corrected package names\"\n }\n ],\n \"error\": {\n \"code\": \"PACKAGE_NOT_FOUND\",\n \"message\": \"Package not found on npm or GitHub\"\n },\n \"data_quality\": \"missing\",\n \"slack_report\": \"string\"\n}"
},
{
"id": "31f6e76d-507f-4968-83f9-e13392a6c893",
"name": "slack report",
"type": "string",
"value": "\u274c *Package Not Found* \n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \n\n \ud83d\udd0d The requested package could not be identified. \n\n\ud83e\uddfe *Observed Facts* \n\n\u2022 No npm package found \n\u2022 No GitHub repository detected \n\u2022 Search results were inconclusive \n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \n\n\ud83e\udde0 *Analysis* \n\n\u2022 Maintenance Risk: \ud83d\udd34 High \n\u2022 Adoption Risk: \ud83d\udd34 High \n\u2022 Data Quality: Missing \n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \n\n\u26a0\ufe0f *Recommendation* \n\n\ud83d\udc49 *Avoid using this package* \n\ud83d\udca1 This package may: \n\u2022 Not exist \n\u2022 Be misspelled \n\u2022 Be private or deprecated \n\n \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 \n\ud83d\udd04 *What you can do* \n\n\u2022 Check spelling of package name \n\u2022 Try similar package names \n\u2022 Search manually on npm \n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "54709ed1-0d1f-467b-987e-4a44da6aaf6f",
"name": "AI Analysis Engine",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
4032,
128
],
"parameters": {
"text": "=Analyze this npm package:\n\nGitHub URL: {{ $('Extract Clean URLs').item.json.github_url }}\nNPM URL: {{ $('Extract Clean URLs').item.json.npm_url }}\n\nPackage: {{ $('Merge All Metrics').item.json.package }}\nGitHub Stars: {{ $('Merge All Metrics').item.json.Github_Stars }}\nOpen Issues: {{ $('Merge All Metrics').item.json.open_issue_count }}\nLast Commit:{{ $('Merge All Metrics').item.json.last_commit_date }}\nWeekly Downloads: {{ $('Merge All Metrics').item.json.downloads }}\n\nAlso consider trends:\nIssue-to-star ratio: {{ $json.issue_to_star_ratio }}\nActivity status: {{ $json.activity_status }}",
"options": {
"systemMessage": "You are an expert software package analyst.\n\nYou analyze npm packages using structured data and external tools.\n\nYour job is to produce:\n\n1. A structured JSON output (for automation)\n2. A Slack-friendly formatted report (for human readability)\n\nYou MUST clearly separate:\n\n* Observed facts (RAW, no interpretation)\n* Inferred judgment (AI reasoning)\n\n---\n\n## AVAILABLE TOOLS\n\nSEARCH tool\n\u2192 Find:\n\n* npm alternatives\n* GitHub repo\n* documentation\n* release notes / roadmap (if needed)\n\nSCRAPE tool\n\u2192 Extract:\n\n* description\n* version\n* GitHub + npm URLs\n* security signals\n* documentation insights\n\n---\n\n## TASK FLOW\n\n### STEP 1 \u2014 VALIDATE PACKAGE\n\nIf package invalid:\n\n* Try typo correction\n* Use SEARCH to find closest match\n\nIf still not found:\nReturn:\n{\n\"error\": \"Package not found\",\n\"suggestions\": [\"string\"]\n}\n\n---\n\n### STEP 2 \u2014 DATA COLLECTION (FACTS ONLY)\n\nCollect RAW data:\n\n* package_name\n* version\n* description (raw)\n* license\n* weekly_downloads\n* github_stars\n* open_issue_count\n* last_commit_date\n* contributors (if available)\n* bundle_size (if available)\n* URLs (npm, GitHub)\n\n---\n\n### STEP 3 \u2014 OBSERVED FACTS (STRICT)\n\nCreate:\n\n\"observed_facts\"\n\nRules:\n\n* ONLY factual statements\n* NO interpretation words (no \"good\", \"high\", etc.)\n* Can include simple factual signals like:\n\n * \"recent commits observed\"\n * \"README present\"\n\nExample types:\n\n* Active development signal (based on commits)\n* Dependency profile (if visible)\n* Docs presence\n\n---\n\n### STEP 4 \u2014 DERIVED METRICS\n\nCompute:\n\nissue_to_star_ratio = open_issue_count / github_stars\n\nactivity_status:\n\n* active \u2192 last commit \u2264 7 days\n* stale \u2192 otherwise\n\n---\n\n### STEP 5 \u2014 INFERRED JUDGMENT (STRICT)\n\nCreate:\n\n\"inferred_judgment\"\n\nMust include:\n\n1. Maintenance risk\n2. Adoption risk\n3. Breaking-change risk (ONLY if evidence exists)\n\nRules:\n\n* MUST include rationale\n* MUST be derived from observed facts\n* Do NOT hallucinate\n\n---\n\n### STEP 6 \u2014 INSIGHTS\n\nGenerate:\n\n* issue_health\n* adoption_level\n* contributor_signal\n* license_insight\n\n---\n\n### STEP 7 \u2014 RISK SCORING\n\nLOW:\n\n* High stars\n* Low issue ratio\n* Active\n\nMEDIUM:\n\n* Moderate signals\n\nHIGH:\n\n* Low stars OR high issues OR stale\n\n---\n\n### STEP 8 \u2014 RECOMMENDATION\n\n* Low \u2192 Use\n* Medium \u2192 Consider\n* High \u2192 Avoid\n\nProvide strong reasoning\n\n---\n\n### STEP 9 \u2014 ALTERNATIVES\n\nReturn 2\u20133 alternatives:\n\nEach must include:\n\n* name\n* tradeoff\n* use_case\n\n---\n\n## OUTPUT REQUIREMENTS\n\nYou MUST return TWO things:\n\n---\n\n# 1\ufe0f\u20e3 STRUCTURED JSON (STRICT)\n\n{\n\"package_info\": {\n\"name\": \"string\",\n\"corrected_name\": \"string\",\n\"current_version\": \"string\"\n},\n\n\"summary_block\": {\n\"description\": \"string\",\n\"summary\": \"string\"\n},\n\n\"links\": {\n\"npm\": \"string\",\n\"github\": \"string\"\n},\n\n\"observed_facts\": [\n\"string\",\n\"string\"\n],\n\n\"inferred_judgment\": {\n\"maintenance_risk\": {\n\"level\": \"Low | Medium | High\",\n\"reason\": \"string\"\n},\n\"adoption_risk\": {\n\"level\": \"Low | Medium | High\",\n\"reason\": \"string\"\n},\n\"breaking_change_risk\": {\n\"status\": \"Low | Medium | High | Unknown\",\n\"reason\": \"string\"\n}\n},\n\n\"metrics\": {\n\"github_stars\": number,\n\"weekly_downloads\": number,\n\"open_issues\": number,\n\"last_commit\": \"string\",\n\"issue_to_star_ratio\": number\n},\n\n\"health\": {\n\"activity_status\": \"active | stale\",\n\"issue_health\": \"string\",\n\"contributor_signal\": \"string\"\n},\n\n\"popularity\": {\n\"score\": \"Low | Medium | High\",\n\"adoption_level\": \"string\",\n\"downloads_badge\": \"string\"\n},\n\n\"risk\": {\n\"level\": \"Low | Medium | High\",\n\"score\": number,\n\"color\": \"green | orange | red\",\n\"reason\": \"string\"\n},\n\n\"license\": {\n\"type\": \"string\",\n\"insight\": \"string\"\n},\n\n\"security\": {\n\"vulnerabilities\": \"string\",\n\"status\": \"safe | warning | risky\"\n},\n\n\"alternatives\": [\n{\n\"name\": \"string\",\n\"tradeoff\": \"string\",\n\"use_case\": \"string\"\n}\n],\n\n\"decision\": {\n\"recommendation\": \"Use | Consider | Avoid\",\n\"confidence\": number,\n\"reason\": \"string\"\n}\n}\n\n---\n\n# 2\ufe0f\u20e3 SLACK REPORT\n\nGenerate a clean Slack-friendly report EXACTLY like:\n\n---\n\n*\ud83d\udce6 *Package Report: axios*\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\ud83d\udcca *Overview*\n\n\u2022 Version: 1.14.0 \n\u2022 Description: Promise-based HTTP client for browser & Node.js \n\u2022 License: MIT (Safe for commercial use)\n\n\ud83d\udcc8 *Key Metrics*\n\n\u2022 \u2b50 Stars: 109k \n\u2022 \ud83d\udce6 Downloads: 91M+/week \n\u2022 \ud83d\udc1e Open Issues: 303 \n\u2022 \ud83d\udd01 Last Commit: Recent (Active)\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\ud83e\uddfe *Observed Facts*\n\n\u2022 Active development (recent commits) \n\u2022 High adoption (91M+ weekly downloads) \n\u2022 Strong community (100k+ stars) \n\u2022 Documentation available and clear \n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\ud83e\udde0 *Inferred Insights*\n\n\u2022 Maintenance Risk: \ud83d\udfe2 Low \n\u2022 Adoption Risk: \ud83d\udfe2 Low \n\u2022 Breaking Change Risk: \ud83d\udfe1 Low likelihood (no strong signals)\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\u26a0\ufe0f *Risk Analysis*\n\n\ud83d\udfe2 *Low Risk* \nReason: High stars, low issue ratio, active development\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\ud83d\udd04 *Alternatives*\n\n\u2022 Got \u2192 Modern, feature-rich (Node.js only) \n\u2022 Ky \u2192 Lightweight fetch wrapper (browser-first) \n\u2022 Node-fetch \u2192 Native fetch style (less features)\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\n\u2705 *Final Recommendation*\n\n\ud83d\udc49 *Use*\n\n\ud83d\udca1 Axios is stable, widely adopted, and actively maintained \u2014 safe for production use.\n## STRICT RULES\n\n* ALWAYS separate observed vs inferred\n* NEVER mix them\n* NEVER hallucinate\n* If missing \u2192 \"unknown\"\n* Always return valid JSON\n* Slack output must be clean markdown\n"
},
"promptType": "define",
"needsFallback": true,
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 3.1
},
{
"id": "921966a2-86cc-431c-a2c0-df9a97979f0f",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
4304,
448
],
"parameters": {
"autoFix": true,
"jsonSchemaExample": "{\n \"package_info\": {\n \"name\": \"string\",\n \"corrected_name\": \"string\",\n \"current_version\": \"string\"\n },\n \"summary_block\": {\n \"description\": \"string\",\n \"summary\": \"string\"\n },\n \"links\": {\n \"npm\": \"string\",\n \"github\": \"string\"\n },\n \"observed_facts\": [\n \"string\"\n ],\n \"inferred_judgment\": {\n \"maintenance_risk\": {\n \"level\": \"Low\",\n \"reason\": \"string\"\n },\n \"adoption_risk\": {\n \"level\": \"Low\",\n \"reason\": \"string\"\n },\n \"breaking_change_risk\": {\n \"status\": \"Low\",\n \"reason\": \"string\"\n }\n },\n \"metrics\": {\n \"github_stars\": 0,\n \"weekly_downloads\": 0,\n \"open_issues\": 0,\n \"last_commit\": \"string\",\n \"issue_to_star_ratio\": 0\n },\n \"health\": {\n \"activity_status\": \"active\",\n \"issue_health\": \"string\",\n \"contributor_signal\": \"string\"\n },\n \"popularity\": {\n \"score\": \"High\",\n \"adoption_level\": \"Very popular\",\n \"downloads_badge\": \"string\"\n },\n \"risk\": {\n \"level\": \"Low\",\n \"score\": 0.0,\n \"color\": \"green\",\n \"reason\": \"string\"\n },\n \"license\": {\n \"type\": \"string\",\n \"insight\": \"string\"\n },\n \"security\": {\n \"vulnerabilities\": \"string\",\n \"status\": \"safe\"\n },\n \"alternatives\": [\n {\n \"name\": \"string\",\n \"tradeoff\": \"string\",\n \"use_case\": \"string\"\n }\n ],\n \"decision\": {\n \"recommendation\": \"Use\",\n \"confidence\": 0.0,\n \"reason\": \"string\"\n },\n \"slack_report\": \"string\"\n}"
},
"retryOnFail": true,
"typeVersion": 1.3
},
{
"id": "f2907960-eb66-4e47-99b1-450c106e0263",
"name": "Send Slack Report",
"type": "n8n-nodes-base.slack",
"position": [
4416,
144
],
"parameters": {
"text": "={{ $json.output.slack_report }}",
"user": {
"__rl": true,
"mode": "list",
"value": "U0AS8B0F3S4",
"cachedResultName": "guptadivyanshu765"
},
"select": "user",
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "311a44bf-76b1-4652-8374-c8dfc125de3b",
"name": "Send Slack Report_01",
"type": "n8n-nodes-base.slack",
"position": [
4240,
1232
],
"parameters": {
"text": "={{ $json['slack report'] }}",
"user": {
"__rl": true,
"mode": "list",
"value": "U0AS8B0F3S4",
"cachedResultName": "guptadivyanshu765"
},
"select": "user",
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "b0693b0a-1d12-47db-9626-c3c40fcafcda",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
352,
48
],
"parameters": {
"width": 992,
"height": 704,
"content": "## INPUT + URL DISCOVERY (Firecrawl Layer)\n\n### \ud83d\udce5 Input & \ud83d\udd25 Firecrawl Discovery\n\n\u2022 User provides npm package name via form\n\u2022 Input is normalized for consistency\n\n### \ud83d\udd25 Firecrawl is used to dynamically discover:\n\u2022 Official npm package page\n\u2022 Correct GitHub repository\n\n### Why this matters:\n\u2022 Avoids hardcoded URLs\n\u2022 Works for ANY package (even unknown ones)\n\u2022 Handles typos and ambiguous names\n\n\ud83d\udc49 This is the \"discovery layer\" of the workflow\n\n\n"
},
"typeVersion": 1
},
{
"id": "96bd1c88-0e35-4fdd-a61b-aa1dc27492bf",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1376,
48
],
"parameters": {
"width": 432,
"height": 704,
"content": "## URL CLEANING + VALIDATION\n\n### \ud83e\udde0 URL Extraction & Validation\n\n\u2022 Filters Firecrawl results to extract:\n\u2192 Clean npm URL\n\u2192 Valid GitHub repo URL\n\n\u2022 Removes noisy links:\n\u2192 issues / pull / commit / blob\n\n\u2022 Adds fallback:\n\u2192 If npm not found \u2192 build default npm URL\n\n\ud83d\udc49 Ensures only usable, production-ready URLs move forward\n\n\n\n"
},
"typeVersion": 1
},
{
"id": "c1c21aa7-c255-4e77-8e73-7e0ca1856d8a",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1840,
48
],
"parameters": {
"width": 880,
"height": 704,
"content": "## DATA COLLECTION (APIs Layer)\n\n### \ud83d\udcca Data Collection (API Layer)\n\nReal-time data is fetched using APIs:\n\n\u2022 GitHub API:\n\u2192 Stars\n\u2192 Open issues\n\u2192 License\n\u2192 Last commit activity\n\n\u2022 npm API:\n\u2192 Weekly download count\n\nWhy APIs (not scraping)?\n\u2022 More reliable\n\u2022 Faster\n\u2022 No JS-rendering issues\n\n\ud83d\udc49 This replaces unreliable HTML scraping\n\n\n\n\n"
},
"typeVersion": 1
},
{
"id": "0bb7eab3-d246-4de0-bcf6-709788750f4c",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2752,
48
],
"parameters": {
"width": 880,
"height": 704,
"content": "## METRICS + VALIDATION LOGIC\n\n### \ud83d\udcc8 Metrics & Validation\n\n\u2022 Combines all collected data\n\u2022 Computes key signals:\n\n\u2192 Issue-to-star ratio\n\u2192 Activity status (active/stale)\n\n\u2022 Validates package existence:\n\u2192 If no GitHub data \u2192 treated as invalid\n\n\ud83d\udc49 Converts raw data \u2192 meaningful signals\n\n\n\n\n\n"
},
"typeVersion": 1
},
{
"id": "56e75c45-d44d-4c82-8a93-4133e343e908",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
3968,
928
],
"parameters": {
"width": 528,
"height": 544,
"content": "## ERROR HANDLING\n\n### \u274c Error Handling & Fallback\n\nHandles edge cases:\n\n\u2022 Package not found\n\u2022 API failures\n\u2022 Missing or incomplete data\n\nReturns:\n\u2022 Safe default recommendation\n\u2022 Helpful explanation\n\u2022 Suggested next steps\n\n\ud83d\udc49 Ensures workflow never breaks\n\n\n\n\n\n\n"
},
"typeVersion": 1
},
{
"id": "ac9c58bc-055a-44ed-ad4c-04e1cd6448fd",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
3664,
48
],
"parameters": {
"width": 896,
"height": 704,
"content": "## AI ANALYSIS + OUTPUT\n\n### \ud83e\udd16 AI Analysis & Reporting\n\nAI Agent performs:\n\n\u2022 Summary generation\n\u2022 Risk scoring (Low / Medium / High)\n\u2022 Adoption & health insights\n\u2022 Recommendation (Use / Consider / Avoid)\n\n### \ud83d\udd25 Firecrawl tools are also used here for:\n\u2022 Context enrichment\n\u2022 Alternative discovery\n\nFinal Output:\n\u2022 Structured JSON\n\u2022 Slack-ready formatted report\n\n\ud83d\udc49 This is the \"decision-making brain\" of the workflow\n\n\n\n\n\n\n"
},
"typeVersion": 1
}
],
"active": true,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "c5041fa5-4dc1-45a8-8ee5-b9e9aa300906",
"connections": {
"Commit deatils": {
"main": [
[
{
"node": "Fetch NPM Downloads",
"type": "main",
"index": 0
},
{
"node": "Merge All Metrics",
"type": "main",
"index": 1
}
]
]
},
"Github details": {
"main": [
[
{
"node": "Fetch Last Commit",
"type": "main",
"index": 0
},
{
"node": "Merge All Metrics",
"type": "main",
"index": 2
}
]
]
},
"Search NPM URL": {
"main": [
[
{
"node": "Search GitHub Repo",
"type": "main",
"index": 0
},
{
"node": "Merge Search Results",
"type": "main",
"index": 0
}
]
]
},
"Normalize Input": {
"main": [
[
{
"node": "Search NPM URL",
"type": "main",
"index": 0
}
]
]
},
"Fetch Last Commit": {
"main": [
[
{
"node": "Commit deatils",
"type": "main",
"index": 0
}
]
]
},
"Merge All Metrics": {
"main": [
[
{
"node": "Compute Health Metrics",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Analysis Engine",
"type": "ai_languageModel",
"index": 1
}
]
]
},
"AI Analysis Engine": {
"main": [
[
{
"node": "Send Slack Report",
"type": "main",
"index": 0
}
]
]
},
"Enter Package Name": {
"main": [
[
{
"node": "Normalize Input",
"type": "main",
"index": 0
}
]
]
},
"Extract Clean URLs": {
"main": [
[
{
"node": "Fetch GitHub Stats",
"type": "main",
"index": 0
}
]
]
},
"Fetch GitHub Stats": {
"main": [
[
{
"node": "Github details",
"type": "main",
"index": 0
}
]
]
},
"Search GitHub Repo": {
"main": [
[
{
"node": "Merge Search Results",
"type": "main",
"index": 1
}
]
]
},
"Check Package Valid": {
"main": [
[
{
"node": "AI Analysis Engine",
"type": "main",
"index": 0
}
],
[
{
"node": "Package Not Found Handler",
"type": "main",
"index": 0
}
]
]
},
"Fetch NPM Downloads": {
"main": [
[
{
"node": "Merge All Metrics",
"type": "main",
"index": 0
}
]
]
},
"/scrape in Firecrawl": {
"ai_tool": [
[
{
"node": "AI Analysis Engine",
"type": "ai_tool",
"index": 0
}
]
]
},
"/search in Firecrawl": {
"ai_tool": [
[
{
"node": "AI Analysis Engine",
"type": "ai_tool",
"index": 0
}
]
]
},
"Merge Search Results": {
"main": [
[
{
"node": "Extract Clean URLs",
"type": "main",
"index": 0
}
]
]
},
"Compute Health Metrics": {
"main": [
[
{
"node": "Check Package Valid",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "Structured Output Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "AI Analysis Engine",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Google Gemini Chat Model1": {
"ai_languageModel": [
[
{
"node": "AI Analysis Engine",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Package Not Found Handler": {
"main": [
[
{
"node": "Send Slack Report_01",
"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.
firecrawlApigithubOAuth2ApigooglePalmApiopenAiApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow analyzes any npm package and delivers a data-driven recommendation using Firecrawl + APIs + AI reasoning.
Source: https://n8n.io/workflows/14911/ — 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.
This is an automated blog post generation system that: Researches topics using AI agents and web search tools Writes complete blog posts with proper SEO structure Generates custom images for each post
This workflow generates comprehensive B2B leads, from a selected Business type in ANY CITY IN THE WORLD, including: Company name; Website; Email (enriched with AI Agent); Phone number; Address; Main L
Content - Write Best Tools In Category Article. Uses formTrigger, httpRequest, slack, chainLlm. Event-driven trigger; 41 nodes.
Turn any product page into ready-to-run Meta ads—fast, consistent, and client-friendly.
My workflow 250630. Uses httpRequest, lmChatOpenAi, outputParserStructured, gmail. Event-driven trigger; 37 nodes.