This workflow corresponds to n8n.io template #16479 — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "HHRhCg2X00IauLhl",
"name": "\ud83c\udfaf Mind the Gap \u2014 Job-market skill-demand radar (LLM + webhook)",
"tags": [],
"nodes": [
{
"id": "9d482430-a708-4eda-9835-15c7288d4fe9",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-560,
-32
],
"parameters": {
"width": 480,
"height": 832,
"content": "## \ud83c\udfaf Mind the Gap \u2014 Job-market skill-demand radar (LLM + webhook)\n\n### How it works\n\nThis workflow produces a web-based job-market skill-demand radar from a webhook or manual run. It loads the desired role and the user\u2019s current skills, serves a cached HTML radar when inputs have not changed, or fetches recent remote jobs, ranks relevant postings, asks an LLM to extract skills, and renders the demand-versus-gap report as HTML.\n\n### Setup steps\n\n- Configure the webhook URL/path and activate the workflow so the radar can be opened in a browser.\n- Edit the \u201cDesired job config\u201d node with the target role, keywords, LLM endpoint/model settings, and any required API key or authorization header.\n- Edit the \u201cYour Skills\u201d node with the user\u2019s CV text, skill list, tools, or background to compare against market demand.\n- Run the \u201cManual test\u201d trigger once to validate the LLM request/response format and confirm the rendered HTML looks correct.\n\n### Customization\n\nAdjust the target role keywords, ranking rules, cache freshness logic, job source, LLM model, and radar rendering thresholds to tune the analysis for a specific market or career path."
},
"typeVersion": 1
},
{
"id": "0ff04a64-3f0b-42fc-ac82-d18b826c3169",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
-32
],
"parameters": {
"color": 7,
"width": 240,
"height": 512,
"content": "## Start radar request\n\nEntry points for opening the radar through the webhook or running the workflow manually for testing."
},
"typeVersion": 1
},
{
"id": "423a9925-f6c1-44d6-8490-a81e2a55b7d3",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
320,
64
],
"parameters": {
"color": 7,
"width": 432,
"height": 320,
"content": "## Configure target profile\n\nDefines the target job search configuration and the user\u2019s known skills that will be used for comparison."
},
"typeVersion": 1
},
{
"id": "333758e0-9166-41b0-b7b5-87a09883f78d",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
832,
64
],
"parameters": {
"color": 7,
"width": 432,
"height": 320,
"content": "## Check cached output\n\nDetermines whether the current inputs match a fresh cached radar page and either returns it immediately or continues to recompute results."
},
"typeVersion": 1
},
{
"id": "754f0efc-c8c4-4d75-9d91-a94dd2942bb4",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1360,
320
],
"parameters": {
"color": 7,
"width": 432,
"height": 320,
"content": "## Fetch and rank jobs\n\nRetrieves recent remote job postings from the configured source, filters them by keywords, ranks them for relevance, and caps the result set."
},
"typeVersion": 1
},
{
"id": "c9b90795-0243-42b7-8fe9-d9f9440798a6",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1840,
320
],
"parameters": {
"color": 7,
"width": 672,
"height": 320,
"content": "## Extract demanded skills\n\nBuilds per-job extraction prompts, sends them to the LLM endpoint, parses the responses, canonicalizes skills, and emits structured skill-demand rows."
},
"typeVersion": 1
},
{
"id": "073a9849-0d2b-4ca7-8f91-4843379768c1",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
2560,
272
],
"parameters": {
"color": 7,
"width": 240,
"height": 368,
"content": "## Render radar page\n\nAggregates extracted market demand, compares it against the user\u2019s skills, and builds the final inlined HTML radar visualization."
},
"typeVersion": 1
},
{
"id": "7be4e3b4-cae9-4b78-98b5-13fb4c22d308",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
2848,
32
],
"parameters": {
"color": 7,
"width": 240,
"height": 336,
"content": "## Return HTML response\n\nSends either the cached page or the newly rendered radar page back to the webhook caller as HTML."
},
"typeVersion": 1
},
{
"id": "view",
"name": "Webhook for Radar View",
"type": "n8n-nodes-base.webhook",
"onError": "continueRegularOutput",
"position": [
48,
144
],
"parameters": {
"path": "mind-the-gap",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "manual",
"name": "Trigger Manually",
"type": "n8n-nodes-base.manualTrigger",
"position": [
48,
320
],
"parameters": {},
"typeVersion": 1
},
{
"id": "gate",
"name": "Manage Cache Stability",
"type": "n8n-nodes-base.code",
"position": [
880,
224
],
"parameters": {
"jsCode": "// Serve the cached page so refreshes are STABLE \u2014 but recompute whenever the inputs change.\n// Cache is reused only if: same keywords + same skills text, younger than cacheHours, and the\n// caller didn't pass ?refresh=1. Editing Config or Registry busts the cache automatically.\nconst cacheHours = 24;\nconst store = $getWorkflowStaticData('global');\nconst c = store.radar;\nconst sig = JSON.stringify({\n k: $('Set Job Search Criteria').first().json.keywords || [],\n s: $('Record Your Skills Data').first().json.skillsText || '',\n});\nlet force = false, viaWebhook = true;\ntry { force = String(($('Webhook for Radar View').first().json.query || {}).refresh || '') === '1'; }\ncatch (e) { viaWebhook = false; } // manual runs always recompute (handy for testing)\nconst fresh = viaWebhook && !force && c && c.html && c.sig === sig && (Date.now() - (c.ts || 0) < cacheHours * 3600 * 1000);\nreturn [{ json: fresh ? { cached: true, html: c.html } : { cached: false } }];"
},
"typeVersion": 2
},
{
"id": "iffresh",
"name": "Check Cache Freshness",
"type": "n8n-nodes-base.if",
"position": [
1120,
224
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c1",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.cached }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "fetch",
"name": "Fetch Recent Job Listings",
"type": "n8n-nodes-base.code",
"position": [
1408,
480
],
"parameters": {
"jsCode": "// One broad, no-auth source (Himalayas \u2014 recent remote jobs across every field). No company list.\n// Free job APIs don't offer real server-side search, so we pull a wide recent window and let the\n// next node filter/rank by your keywords (with a never-empty fallback).\nconst cfg = $('Set Job Search Criteria').first().json;\nconst H = (typeof $helpers !== 'undefined' && $helpers && $helpers.httpRequest) ? $helpers : this.helpers;\nconst s = (v) => (v == null ? '' : String(v));\nconst strip = (h) => s(h).replace(/<[^>]*>/g, ' ').replace(/&[a-z#0-9]+;/g, ' ').replace(/\\s+/g, ' ').trim().slice(0, 1500);\nconst per = cfg.feedPerPage || 100, pages = cfg.feedPages || 4;\nconst out = [];\nfor (let p = 0; p < pages; p++) {\n let hb;\n try { hb = await H.httpRequest({ method: 'GET', url: 'https://himalayas.app/jobs/api?limit=' + per + '&offset=' + (p * per), json: true, timeout: 20000 }); }\n catch (e) { break; }\n for (const j of ((hb && hb.jobs) || [])) {\n out.push({ json: {\n company: s(j.companyName) || 'unknown',\n title: s(j.title),\n description: strip(j.description || j.excerpt),\n posted_at: j.pubDate ? new Date(j.pubDate * 1000).toISOString() : '',\n external_id: 'himalayas:' + s(j.guid || j.title),\n } });\n }\n}\nreturn out;"
},
"typeVersion": 2
},
{
"id": "filter",
"name": "Rank Job Listings",
"type": "n8n-nodes-base.code",
"position": [
1648,
480
],
"parameters": {
"jsCode": "// Keyword filter + relevance rank + cap. Relevance = title hits x3 + description hits x1,\n// tie-broken by recency. Empty keywords => keep the newest 'maxJobs' across the whole feed.\nconst cfg = $('Set Job Search Criteria').first().json;\nconst kw = (cfg.keywords || []).map(k => String(k).toLowerCase()).filter(Boolean);\nconst cap = cfg.maxJobs || 25;\nconst scored = $input.all().map(it => {\n const j = it.json;\n const t = (j.title || '').toLowerCase(), d = (j.description || '').toLowerCase();\n let rel = 0;\n for (const k of kw) { if (t.includes(k)) rel += 3; if (d.includes(k)) rel += 1; }\n return { j, rel };\n});\nlet keep = kw.length ? scored.filter(x => x.rel > 0) : scored;\nif (keep.length === 0) keep = scored; // never drop everything \u2014 keep the feed if nothing matched\nkeep.sort((a, b) => (b.rel - a.rel) || String(b.j.posted_at).localeCompare(String(a.j.posted_at)));\nreturn keep.slice(0, cap).map(x => ({ json: x.j }));"
},
"typeVersion": 2
},
{
"id": "prompt",
"name": "Build Extraction Request",
"type": "n8n-nodes-base.code",
"position": [
1888,
480
],
"parameters": {
"jsCode": "// One extraction request per job (small models handle this fine; calls fail independently).\nconst cfg = $('Set Job Search Criteria').first().json;\nconst clip = (v, n) => String(v == null ? '' : v).replace(/\\s+/g, ' ').trim().slice(0, n);\nconst sys = [\n 'You extract structured skill requirements from a job posting.',\n 'Return ONLY a JSON object: {\"seniority\":\"<one of: junior, mid, senior, staff, lead, unspecified>\",\"skills\":[{\"name\":\"<skill>\",\"importance\":\"<must|nice>\"}]}.',\n '- skills are concrete technologies, tools, languages, methods, or domain competencies named in the posting.',\n '- canonical lowercase names: \"kubernetes\" not K8s, \"go\" not golang, \"ci/cd\" not CICD.',\n '- max 15 skills, most important first. Skip soft skills (communication, teamwork) and filler (engineering, software).',\n '- importance \"must\" if required/essential, \"nice\" if preferred/bonus.',\n].join('\\n');\nreturn $input.all().map(it => {\n const j = it.json;\n const user = 'Job posting:\\n' + JSON.stringify({ title: j.title, company: j.company, description: clip(j.description, 1500) });\n const body = { model: cfg.llmModel, messages: [{ role: 'system', content: sys }, { role: 'user', content: user }], temperature: 0, seed: 7, max_tokens: 500 };\n return { json: { external_id: j.external_id, company: j.company, title: j.title, bodyJson: JSON.stringify(body) } };\n});"
},
"typeVersion": 2
},
{
"id": "llm",
"name": "Post to LLM API",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueRegularOutput",
"position": [
2128,
480
],
"parameters": {
"url": "={{ $('Set Job Search Criteria').first().json.llmUrl }}",
"method": "POST",
"options": {
"timeout": 60000
},
"jsonBody": "={{ $json.bodyJson }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "parse",
"name": "Analyze Extracted Skills",
"type": "n8n-nodes-base.code",
"position": [
2368,
480
],
"parameters": {
"jsCode": "// Align prompts<->responses by index, parse JSON, canonicalize, emit one row per (job, skill).\nconst prompts = $('Build Extraction Request').all().map(i => i.json);\nconst responses = $input.all().map(i => i.json);\nconst CANON = {\n 'k8s': 'kubernetes', 'k3s': 'kubernetes', 'eks': 'aws', 'gke': 'google cloud', 'aks': 'azure',\n 'golang': 'go', 'gcp': 'google cloud', 'amazon web services': 'aws', 'microsoft azure': 'azure',\n 'cicd': 'ci/cd', 'ci cd': 'ci/cd', 'ci-cd': 'ci/cd', 'continuous integration': 'ci/cd',\n 'argo cd': 'argocd', 'iac': 'infrastructure as code', 'tf': 'terraform', 'postgresql': 'postgres',\n 'js': 'javascript', 'ts': 'typescript', 'monitoring': 'observability', 'helm charts': 'helm',\n};\nconst out = [];\nfor (let i = 0; i < responses.length; i++) {\n const p = prompts[i];\n if (!p) continue;\n let parsed = null;\n try {\n const r = responses[i];\n let c = (r && r.choices && r.choices[0] && r.choices[0].message) ? (r.choices[0].message.content || '') : '';\n const m = c.match(/\\{[\\s\\S]*\\}/); if (m) c = m[0];\n parsed = JSON.parse(c);\n } catch (e) { continue; }\n let seniority = String(parsed.seniority || 'unspecified').toLowerCase().trim();\n if (!['junior', 'mid', 'senior', 'staff', 'lead'].includes(seniority)) seniority = 'unspecified';\n const seen = new Set();\n for (const sk of (Array.isArray(parsed.skills) ? parsed.skills : [])) {\n let name = String((sk && sk.name) || '').toLowerCase().trim().replace(/\\s+/g, ' ');\n if (!name) continue;\n if (CANON[name]) name = CANON[name];\n if (name.length > 60 || seen.has(name)) continue;\n seen.add(name);\n out.push({ json: { external_id: p.external_id, company: p.company, title: p.title, skill: name, importance: (sk && String(sk.importance).toLowerCase() === 'must') ? 'must' : 'nice', seniority } });\n }\n}\nreturn out;"
},
"typeVersion": 2
},
{
"id": "render",
"name": "Generate Radar View",
"type": "n8n-nodes-base.code",
"position": [
2608,
480
],
"parameters": {
"jsCode": "// Inlined radar renderer \u2014 aggregate market demand and join it against your free-text skills.\nconst rows = $('Analyze Extracted Skills').all().map(i => i.json);\nconst skillsText = String(($('Record Your Skills Data').first().json || {}).skillsText || '').toLowerCase();\n\nconst demand = {};\nfor (const r of rows) {\n const s = (r.skill || '').toLowerCase().trim();\n if (!s || s === '__none') continue;\n if (!demand[s]) demand[s] = { mentions: 0, must: 0 };\n demand[s].mentions++;\n if (r.importance === 'must') demand[s].must++;\n}\nconst totalJobs = new Set(rows.map(r => r.external_id)).size;\n\n// loose synonym match so \"k8s\" in your text covers demand for \"kubernetes\"\nconst ALIAS = {\n kubernetes: ['k8s', 'k3s', 'eks', 'gke', 'aks'], aws: ['amazon web services'],\n 'google cloud': ['gcp'], azure: ['aks'], 'ci/cd': ['cicd', 'jenkins', 'github actions', 'gitlab ci'],\n go: ['golang'], postgres: ['postgresql'], observability: ['monitoring', 'prometheus', 'grafana'],\n terraform: ['iac'], javascript: ['js'], typescript: ['ts'],\n};\nconst has = (name) => skillsText.includes(name) || (ALIAS[name] || []).some(a => skillsText.includes(a));\n\nconst ranked = Object.entries(demand)\n .map(([name, d]) => ({ name, mentions: d.mentions, must: d.must, weight: d.mentions, covered: has(name) }))\n .sort((a, b) => b.weight - a.weight || b.must - a.must);\n\n// score over the full demand; show only the most-wanted skills so the page stays readable\nlet wSum = 0, wGot = 0;\nfor (const r of ranked) { wSum += r.weight; if (r.covered) wGot += r.weight; }\nconst list = ranked.slice(0, 30);\nconst score = wSum ? Math.round((wGot / wSum) * 100) : 0;\nconst maxW = Math.max(1, ...list.map(r => r.weight));\n\nconst esc = v => String(v ?? '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\nconst bar = w => `<div class=\"bar\"><div style=\"width:${Math.round((w / maxW) * 100)}%\"></div></div>`;\nconst tr = r => {\n const [c, l] = r.covered ? ['#22c55e', 'have'] : ['#ef4444', 'gap'];\n return `<tr><td><b>${esc(r.name)}</b></td><td>${bar(r.weight)}<span class=\"n\">${r.mentions} of ${totalJobs} jobs${r.must ? ` \u00b7 ${r.must} must` : ''}</span></td><td><span class=\"chip\" style=\"background:${c}22;color:${c};border-color:${c}55\">${l}</span></td></tr>`;\n};\nconst empty = list.length === 0;\n\nconst html = `<!doctype html>\n<html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<meta name=\"robots\" content=\"noindex,nofollow\"><title>mind the gap</title><style>\n:root{color-scheme:dark} body{margin:0;background:#0b0e14;color:#cdd6e4;font:15px/1.5 ui-monospace,Menlo,monospace}\nmain{max-width:820px;margin:0 auto;padding:40px 20px 80px}\nh1{font-size:22px;color:#e8eefb;margin:0} h2{font-size:13px;color:#8b97ab;margin:32px 0 8px;text-transform:uppercase;letter-spacing:.1em}\n.score{font-size:56px;color:#e8eefb;font-weight:700;margin:16px 0 2px} .sub{color:#67738a;font-size:13px}\ntable{width:100%;border-collapse:collapse;margin-top:8px} td{padding:9px 10px;border-top:1px solid #1c2230;vertical-align:top}\ntd:nth-child(2){width:260px} td:nth-child(3){width:90px;text-align:right}\n.bar{background:#1c2230;border-radius:3px;height:8px;overflow:hidden;margin-top:6px} .bar div{background:#3b82f6;height:100%}\n.n{font-size:12px;color:#67738a} .chip{display:inline-block;padding:2px 9px;border-radius:999px;font-size:12px;border:1px solid}\nfooter{margin-top:60px;font-size:12px;color:#2c3548;text-align:center}\n</style></head><body><main>\n<h1>mind the gap</h1>\n<div class=\"sub\">market demand vs. your skills \u2014 ${totalJobs} job${totalJobs === 1 ? '' : 's'} scanned${empty ? '' : ', skills ranked by how many list them'}</div>\n${empty ? '<p class=\"sub\" style=\"margin-top:30px\">No skills extracted yet. Check the keywords in the <b>Config</b> node and that your LLM credential is set on <b>Extract (LLM)</b>.</p>' : `\n<div class=\"score\">${score}%</div>\n<div class=\"sub\">share of in-demand skills your text covers \u00b7 updated ${new Date().toISOString().slice(0, 16).replace('T', ' ')} UTC</div>\n<h2>demand radar</h2>\n<table>${list.map(tr).join('\\n')}</table>`}\n<footer>\u00b7</footer>\n</main></body></html>`;\n\n// cache the finished page in the workflow's static data so refreshes are STABLE\n// (served by the cache gate) until the TTL expires or ?refresh=1 forces a recompute.\nconst store = $getWorkflowStaticData('global');\nconst sig = JSON.stringify({\n k: $('Set Job Search Criteria').first().json.keywords || [],\n s: $('Record Your Skills Data').first().json.skillsText || '',\n});\nstore.radar = { html, ts: Date.now(), sig };\n\nreturn [{ json: { html } }];\n"
},
"typeVersion": 2
},
{
"id": "resp",
"name": "Provide HTML Response",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2896,
208
],
"parameters": {
"options": {
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "text/html; charset=utf-8"
}
]
}
},
"respondWith": "text",
"responseBody": "={{ $json.html }}"
},
"typeVersion": 1.5
},
{
"id": "config",
"name": "Set Job Search Criteria",
"type": "n8n-nodes-base.code",
"position": [
368,
224
],
"parameters": {
"jsCode": "// EDIT THIS \u2014 what role / skills are you scanning the market for?\nconst config = {\n keywords: [\"engineer\"], // ANY role/skills \u2014 e.g. [\"product manager\"], [\"nurse\"]. Empty = whole feed.\n maxJobs: 25, // one LLM call per job in a single pass \u2014 keep this modest.\n feedPages: 4, feedPerPage: 100,\n llmUrl: \"https://integrate.api.nvidia.com/v1/chat/completions\", // any OpenAI-compatible endpoint\n llmModel: \"meta/llama-3.1-8b-instruct\",\n};\nreturn [{ json: config }];"
},
"typeVersion": 2
},
{
"id": "registry",
"name": "Record Your Skills Data",
"type": "n8n-nodes-base.code",
"position": [
608,
224
],
"parameters": {
"jsCode": "// EDIT THIS \u2014 paste anything that describes what you know: a CV paragraph, a list of tools,\n// prose, comma-separated keywords. No format and no proof required. Any skill the market\n// wants that also appears in this text counts as one you \"have\"; the rest are gaps.\nconst skillsText = `python, javascript, typescript, react, node, sql, postgres, aws, docker, kubernetes,\nterraform, ci/cd, linux, git, rest api, communication, agile, project management\nI've built and run Grafana/Prometheus monitoring in production and write a lot of Bash and Go.`;\n\nreturn [{ json: { skillsText } }];\n"
},
"typeVersion": 2
}
],
"active": true,
"settings": {
"binaryMode": "separate",
"callerPolicy": "workflowsFromSameOwner",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "3ae46e86-9065-4ff8-9f6e-b295382eccf0",
"connections": {
"Post to LLM API": {
"main": [
[
{
"node": "Analyze Extracted Skills",
"type": "main",
"index": 0
}
]
]
},
"Trigger Manually": {
"main": [
[
{
"node": "Set Job Search Criteria",
"type": "main",
"index": 0
}
]
]
},
"Rank Job Listings": {
"main": [
[
{
"node": "Build Extraction Request",
"type": "main",
"index": 0
}
]
]
},
"Generate Radar View": {
"main": [
[
{
"node": "Provide HTML Response",
"type": "main",
"index": 0
}
]
]
},
"Check Cache Freshness": {
"main": [
[
{
"node": "Provide HTML Response",
"type": "main",
"index": 0
}
],
[
{
"node": "Fetch Recent Job Listings",
"type": "main",
"index": 0
}
]
]
},
"Manage Cache Stability": {
"main": [
[
{
"node": "Check Cache Freshness",
"type": "main",
"index": 0
}
]
]
},
"Webhook for Radar View": {
"main": [
[
{
"node": "Set Job Search Criteria",
"type": "main",
"index": 0
}
]
]
},
"Record Your Skills Data": {
"main": [
[
{
"node": "Manage Cache Stability",
"type": "main",
"index": 0
}
]
]
},
"Set Job Search Criteria": {
"main": [
[
{
"node": "Record Your Skills Data",
"type": "main",
"index": 0
}
]
]
},
"Analyze Extracted Skills": {
"main": [
[
{
"node": "Generate Radar View",
"type": "main",
"index": 0
}
]
]
},
"Build Extraction Request": {
"main": [
[
{
"node": "Post to LLM API",
"type": "main",
"index": 0
}
]
]
},
"Fetch Recent Job Listings": {
"main": [
[
{
"node": "Rank Job Listings",
"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.
httpHeaderAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Turn a job search into a measured system. This workflow scrapes live job posts, uses an LLM to extract the skills each one is asking for, compares that demand against the skills you list, and serves the result as a live radar page. 🌐 Open the webhook URL → the run starts. ♻️…
Source: https://n8n.io/workflows/16479/ — 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 n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.
This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c