{
"id": "D0I76cew5KOnlem0",
"meta": {
"instanceId": "workflow-1b1535dc",
"versionId": "1.0.0",
"createdAt": "2025-09-29T07:07:43.271592",
"updatedAt": "2025-09-29T07:07:43.271608",
"owner": "n8n-user",
"license": "MIT",
"category": "automation",
"status": "active",
"priority": "high",
"environment": "production"
},
"name": "Workflow stats",
"tags": [
"automation",
"n8n",
"production-ready",
"excellent",
"optimized"
],
"nodes": [
{
"id": "b1a73981-db6a-4fd2-9cad-d02bfecc7d3d",
"name": "When clicking \"Test workflow\"",
"type": "n8n-nodes-base.manualTrigger",
"position": [
1060,
740
],
"parameters": {},
"typeVersion": 1,
"notes": "This manualTrigger node performs automated tasks as part of the workflow."
},
{
"id": "cbe2d1a8-51e9-4f3d-8ca5-321f3edf9a92",
"name": "nodes-section",
"type": "n8n-nodes-base.code",
"position": [
1900,
800
],
"parameters": {
"jsCode": "// Initialize an empty object to hold the mapping between nodes and workflows\nconst nodeToWorkflowsMap = {};\n\n// Iterate over each workflow in the input\n$input.all().forEach(item => {\n const { wf_stats } = item.json;\n const { nodes_unique, wf_name, wf_url, wf_id } = wf_stats;\n\n // For each unique node in the workflow, update the mapping\n nodes_unique.forEach(node => {\n if (!nodeToWorkflowsMap[node]) {\n // If the node has not been added to the map, initialize it with the current workflow\n nodeToWorkflowsMap[node] = [{ wf_name, wf_url, wf_id }];\n } else {\n // If the node is already in the map, append the current workflow to its list\n nodeToWorkflowsMap[node].push({ wf_name, wf_url, wf_id });\n }\n });\n});\n\n// Convert the map into an array format suitable for n8n's output\nconst result = Object.keys(nodeToWorkflowsMap).map(node => ({\n json: {\n node,\n count: nodeToWorkflowsMap[node].length,\n workflows: nodeToWorkflowsMap[node]\n }\n}));\n\nreturn result;"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "49a10bf3-f2e6-4fe9-8390-2a266f1b52a9",
"name": "workflows-section",
"type": "n8n-nodes-base.set",
"position": [
1680,
640
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "fd4aa80c-cd88-4a97-b943-dfcf1ab222ee",
"name": "wf_stats",
"type": "object",
"value": "={{ { nodes_unique :[...new Set($json.nodes_array)],\n nodes_count_total:$json.nodes_array.length,\n nodes_count_uniq :[...new Set($json.nodes_array)].length,\n wf_created :DateTime.fromISO($json.createdAt).toFormat('yyyy-MM-dd HH:mm:ss'),\n wf_updated :DateTime.fromISO($json.updatedAt).toFormat('yyyy-MM-dd HH:mm:ss'),\n wf_name :$json.name,\n wf_id :`wf-${$json.id}`,\n wf_url :`${$json.instance_url}/workflow/${$json.id}` || \"\",\n wf_active :$json.active,\n wf_trigcount :$json.triggerCount,\n wf_tags :$json.tags_array,\n wf_whooks :$json.webhook_paths_array\n\n} }}"
}
]
}
},
"typeVersion": 3.3,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "afbbc6a0-dcb8-48e7-b2d1-ef00c769d3b7",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
1240,
-120
],
"parameters": {
"width": 1490,
"height": 1375,
"content": "## Create the main JSON object with the workflow statistics\n* `globals` - general information (# of workflows, active workflows, total trigger count)\n* `wf_stats` - summary per workflow (number or nodes, unique nodes, list of nodes and tags)\n* `nodes-section` - summary per node (number of workflows that use a node and their URLs)\n* `tags-section` - summary per tag (number of workflows that use a node and their URLs)\n* `webhook-section` - lists all webhook endpoints of the instance and shows the workflow URLs\n\n### You can use this JSON in BI tools to create a custom dashboard\n\n## Learn JS tips & tricks\n### Instead of just using one Code node, the workflow contains several nodes with useful advanced tricks.\n\n### JMESPath\n* Make a simple array of strings out of a complex array: `$jmespath($json,'nodes[*].type')`\n* Extract values based on condition: `$jmespath($input.all(),'[?json.wf_stats.wf_active == `true`]')`\n\n### Map and arrow functions\n* Perform operation on each array element: `.map(item => (item.split('.').pop().toUpperCase() ))`\n* Calculate sum of values from an array: `.reduce((accumulator, currentValue) => accumulator + currentValue, 0)`\n\n### Create an array with only unique values\n* `[...new Set($json.nodes_array)]`\n\n### Date-time conversions with the Luxon library:\n* `DateTime.fromISO($json.createdAt).toFormat('yyyy-MM-dd HH:mm:ss')`\n\n### Template literals (Template strings) for creating strings in JS\n* `wf-${$json.id}`"
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "9dcb369b-fe22-45e1-906d-848a85b0c1e4",
"name": "tags-section",
"type": "n8n-nodes-base.code",
"position": [
1900,
960
],
"parameters": {
"jsCode": "// Initialize an empty object to hold the mapping between tags and workflows\nconst tagToWorkflowsMap = {};\n\n// Iterate over each workflow in the input\n$input.all().forEach(item => {\n const { wf_stats } = item.json;\n // Destructure wf_url along with other properties\n const { wf_tags, wf_name, wf_id, wf_url } = wf_stats;\n\n // Check if the workflow has tags\n if (wf_tags && wf_tags.length > 0) {\n // For each tag in the workflow, update the mapping\n wf_tags.forEach(tag => {\n if (!tagToWorkflowsMap[tag]) {\n // If the tag has not been added to the map, initialize it with the current workflow including wf_url\n tagToWorkflowsMap[tag] = [{ wf_name, wf_id, wf_url }];\n } else {\n // If the tag is already in the map, append the current workflow to its list including wf_url\n tagToWorkflowsMap[tag].push({ wf_name, wf_id, wf_url });\n }\n });\n } else {\n // Handle workflows with no tags, categorizing them under a 'No Tags' category\n const noTagKey = 'No Tags'; // or any other placeholder you prefer\n if (!tagToWorkflowsMap[noTagKey]) {\n // Initialize with the current workflow including wf_url\n tagToWorkflowsMap[noTagKey] = [{ wf_name, wf_id, wf_url }];\n } else {\n // Append the current workflow to its list including wf_url\n tagToWorkflowsMap[noTagKey].push({ wf_name, wf_id, wf_url });\n }\n }\n});\n\n// Convert the map into an array format suitable for n8n's output\nconst result = Object.keys(tagToWorkflowsMap).map(tag => ({\n json: {\n tag,\n count: tagToWorkflowsMap[tag].length,\n workflows: tagToWorkflowsMap[tag] // This now contains objects with wf_name, wf_id, and wf_url\n }\n}));\n\nreturn result;"
},
"typeVersion": 2,
"notes": "This code node performs automated tasks as part of the workflow."
},
{
"id": "7509c96c-0907-4cf1-94cf-f9dfbc0d3f9d",
"name": "globals-section",
"type": "n8n-nodes-base.set",
"position": [
1900,
520
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9e1284bd-73c5-4d3d-bb5d-3437fca97780",
"name": "globals",
"type": "object",
"value": "={{ { global_total : $input.all().length,\n global_active : $jmespath($input.all(),'[?json.wf_stats.wf_active == `true`]').length,\n global_trigger: $jmespath($input.all(),'[].json.wf_stats.wf_trigcount').reduce((accumulator, currentValue) => accumulator + currentValue, 0) } }}"
}
]
}
},
"executeOnce": true,
"typeVersion": 3.3,
"notes": "This set node performs automated tasks as part of the workflow."
},
{
"id": "2c0bc2dd-63d9-4b65-9e4e-2920892efaf7",
"name": "Execute Workflow Trigger",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
1060,
540
],
"parameters": {},
"typeVersion": 1,
"notes": "This executeWorkflowTrigger node performs automated tasks as part of the workflow."
},
{
"id": "8bceb3e9-e1d9-4ca0-af91-5377d4300346",
"name": "Convert to XML",
"type": "n8n-nodes-base.xml",
"position": [
1480,
1600
],
"parameters": {
"mode": "jsonToxml",
"options": {
"headless": true
}
},
"typeVersion": 1,
"notes": "This xml node performs automated tasks as part of the workflow."
},
{
"id": "6151d4b8-f592-418d-b099-17c71b1de0e4",
"name": "Create HTML",
"type": "n8n-nodes-base.html",
"position": [
1680,
1600
],
"parameters": {
"html": "\n\n\n{{ $json.data }}"
},
"typeVersion": 1,
"notes": "This html node performs automated tasks as part of the workflow."
},
{
"id": "e5ebc5c1-0fcc-4f9d-b8eb-df3a367cc097",
"name": "Move Binary Data",
"type": "n8n-nodes-base.moveBinaryData",
"position": [
1880,
1600
],
"parameters": {
"mode": "jsonToBinary",
"options": {
"mimeType": "text/xml",
"keepSource": false,
"useRawData": true
},
"sourceKey": "YOUR_CREDENTIAL_HERE",
"convertAllData": false
},
"typeVersion": 1,
"notes": "This moveBinaryData node performs automated tasks as part of the workflow."
},
{
"id": "5fdb74f7-6b2a-4042-91a2-c2088e8ea712",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2080,
1600
],
"parameters": {
"options": {
"responseCode": 200,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "text/xml"
},
{
"name": "Control-Allow-Origin",
"value": "*"
}
]
}
},
"respondWith": "binary"
},
"typeVersion": 1,
"notes": "This respondToWebhook node performs automated tasks as part of the workflow."
},
{
"id": "ed113e7c-c49f-4854-8fbf-5f7bf3591ede",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1000,
1840
],
"parameters": {
"color": 7,
"width": 909,
"height": 426,
"content": "# DO NOT RUN THIS\n## This webhook is needed to comply with the CORS policy of modern browsers.\n### It generates XML template and serves it using your n8n URL\n\nXSLT template is created with 2 Set nodes:\n1. `Template elements` node defines each section of the Dashboard\n2. `Final template` node puts everything together\n3. Bootstrap 5.3 styling is added. You can save the .css and .js files on your server. Right now a CDN version of the librarly is used."
},
"typeVersion": 1,
"notes": "This stickyNote node performs automated tasks as part of the workflow."
},
{
"id": "b6674f77-7797-4090-a4f9-56a9ddc0d4e0",
"name": "Respond to Webhook2",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1700,
2120
],
"parameters": {
"options": {
"responseCode": 200,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "text/xsl"
}
]
}
},
"respondWith": "text",
"responseBody": "={{ $json.xsl_template }}"
},
"typeVersion": 1,
"notes": "This respondToWebhook node performs automated tasks as part of the workflow."
},
{
"id": "c8c906da-0b61-46b0-be96-11da3c203e3f",
"name": "Final template",
"type": "n8n-nodes-base.set",
"position": [
1500,
2120
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2a42cfed-0451-41c2-9634-865cac2ea68d",
"name": "xsl_template",
"type": "string",
"value": "= 📊 ✅ ⚡ n8n Workflow Dashboard
\nOverview
\n Total Workflows
\n Active Workflows
\n Triggers Count
\n Workflows
\n \n \n
\n Nodes
\n \nWebhooks
\n \n
This dashboard was created using XML template language (XSLT) in n8n.
\n Read Article\nCreates a dynamic Docsify site with GPT-powered descriptions and Mermaid diagrams.
\n \nFeatures live editing, tag filtering, and automated documentation updates for your n8n instance.
\n View Template\nGenerates interactive workflow flowcharts using Mermaid.js and Bootstrap.
\n \nInstantly visualize structures with custom shapes and direct links to workflows, perfect for documentation.
\n View Template\n