{ "nodes": [ { "name": "Webhook", "type": "n8n-nodes-base.webhook", "position": [ 350, 70 ], "webhookId": "727b4887-e7f9-405f-bf94-7889c82a8f0b", "parameters": { "path": "sh", "options": {}, "responseMode": "lastNode" }, "typeVersion": 1 }, { "name": "Extract URL", "type": "n8n-nodes-base.set", "position": [ 650, -80 ], "parameters": { "values": { "string": [ { "name": "url", "value": "={{$node[\"Webhook\"].json[\"query\"][\"url\"]}}" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Check URL", "type": "n8n-nodes-base.if", "position": [ 500, 70 ], "parameters": { "conditions": { "boolean": [ { "value1": "={{Object($node[\"Webhook\"].json[\"query\"]).hasOwnProperty(\"url\")}}", "value2": true } ] } }, "typeVersion": 1 }, { "name": "Crypto", "type": "n8n-nodes-base.crypto", "position": [ 800, -80 ], "parameters": { "type": "SHA256", "value": "={{$node[\"Extract URL\"].json[\"url\"]}}" }, "typeVersion": 1 }, { "name": "Airtable", "type": "n8n-nodes-base.airtable", "position": [ 1550, -30 ], "parameters": { "table": "YOUR TABLE NAME", "options": {}, "operation": "append", "application": "YOUR BASE ID" }, "credentials": { "airtableApi": "Personal Airtable API creds" }, "typeVersion": 1 }, { "name": "Set ID,shortUrl,longUrl", "type": "n8n-nodes-base.set", "position": [ 950, -80 ], "parameters": { "values": { "string": [ { "name": "id", "value": "={{$node[\"Crypto\"].json[\"data\"].substr(0,6)}}" }, { "name": "longUrl", "value": "={{$node[\"Extract URL\"].json[\"url\"]}}" }, { "name": "shortUrl", "value": "=http://n8n.ly/w/go?id={{$node[\"Crypto\"].json[\"data\"].substr(0,6)}}" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Find by ID", "type": "n8n-nodes-base.airtable", "position": [ 1100, -80 ], "parameters": { "limit": 1, "table": "YOUR TABLE NAME", "operation": "list", "returnAll": false, "application": "YOUR BASE ID", "additionalOptions": { "filterByFormula": "=id=\"{{$node[\"Set ID,shortUrl,longUrl\"].json[\"id\"]}}\"" } }, "credentials": { "airtableApi": "Personal Airtable API creds" }, "typeVersion": 1, "alwaysOutputData": true }, { "name": "Already exists ?", "type": "n8n-nodes-base.if", "position": [ 1250, -80 ], "parameters": { "conditions": { "boolean": [ { "value1": "={{$node[\"Find by ID\"].json[\"id\"] != \"\" && $node[\"Find by ID\"].json[\"id\"] != null && $node[\"Find by ID\"].json[\"id\"] != undefined}}", "value2": true } ] } }, "typeVersion": 1 }, { "name": "Set Output", "type": "n8n-nodes-base.set", "position": [ 1400, -180 ], "parameters": { "values": { "string": [ { "name": "shortUrl", "value": "={{$node[\"Set ID,shortUrl,longUrl\"].json[\"shortUrl\"]}}" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Set Error output", "type": "n8n-nodes-base.set", "position": [ 650, 170 ], "parameters": { "values": { "string": [ { "name": "error", "value": "url parameter missing" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Set Output1", "type": "n8n-nodes-base.set", "position": [ 1700, -30 ], "parameters": { "values": { "string": [ { "name": "shortUrl", "value": "={{$node[\"Set ID,shortUrl,longUrl\"].json[\"shortUrl\"]}}" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Set input", "type": "n8n-nodes-base.set", "position": [ 1400, -30 ], "parameters": { "values": { "number": [ { "name": "clicks" } ], "string": [ { "name": "id", "value": "={{$node[\"Crypto\"].json[\"data\"].substr(0,6)}}" }, { "name": "longUrl", "value": "={{$node[\"Extract URL\"].json[\"url\"]}}" }, { "name": "shortUrl", "value": "=http://n8n.ly/w/go?id={{$node[\"Crypto\"].json[\"data\"].substr(0,6)}}" }, { "name": "host", "value": "={{(new URL($node[\"Extract URL\"].json[\"url\"])).host}}" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Webhook1", "type": "n8n-nodes-base.webhook", "position": [ 350, 430 ], "webhookId": "727b4887-e7f9-405f-bf94-7889c82a8f0b", "parameters": { "path": "/go", "options": { "responseHeaders": { "entries": [ { "name": "Content-Type", "value": "text/html" } ] }, "responsePropertyName": "result" }, "responseMode": "lastNode" }, "typeVersion": 1 }, { "name": "Set Error output1", "type": "n8n-nodes-base.set", "position": [ 640, 530 ], "parameters": { "values": { "string": [ { "name": "result", "value": "id parameter missing." } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Check Id", "type": "n8n-nodes-base.if", "position": [ 500, 430 ], "parameters": { "conditions": { "boolean": [ { "value1": "={{Object($node[\"Webhook1\"].json[\"query\"]).hasOwnProperty(\"id\")}}", "value2": true } ] } }, "typeVersion": 1 }, { "name": "Find by ID1", "type": "n8n-nodes-base.airtable", "position": [ 800, 330 ], "parameters": { "limit": 1, "table": "YOUR TABLE NAME", "operation": "list", "returnAll": false, "application": "YOUR BASE ID", "additionalOptions": { "filterByFormula": "=id=\"{{$node[\"Extract Id\"].json[\"id\"]}}\"" } }, "credentials": { "airtableApi": "Personal Airtable API creds" }, "typeVersion": 1, "alwaysOutputData": true }, { "name": "Already exists ?1", "type": "n8n-nodes-base.if", "position": [ 950, 330 ], "parameters": { "conditions": { "boolean": [ { "value1": "={{$node[\"Find by ID1\"].json[\"id\"] != \"\" && $node[\"Find by ID1\"].json[\"id\"] != null && $node[\"Find by ID1\"].json[\"id\"] != undefined}}", "value2": true } ] } }, "typeVersion": 1 }, { "name": "Set Output2", "type": "n8n-nodes-base.set", "position": [ 1400, 230 ], "parameters": { "values": { "string": [ { "name": "result", "value": "=\n\n\n \n \n \n Redirection\n\n\n \n\n\n" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Extract Id", "type": "n8n-nodes-base.set", "position": [ 650, 330 ], "parameters": { "values": { "string": [ { "name": "id", "value": "={{$node[\"Webhook1\"].json[\"query\"][\"id\"]}}" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "404 Error", "type": "n8n-nodes-base.set", "position": [ 1100, 430 ], "parameters": { "values": { "string": [ { "name": "result", "value": "=Short URL not found" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 }, { "name": "Update clicks", "type": "n8n-nodes-base.airtable", "position": [ 1250, 230 ], "parameters": { "id": "={{$node[\"Find by ID1\"].json[\"id\"]}}", "table": "YOUR TABLE NAME", "fields": [ "clicks" ], "options": {}, "operation": "update", "application": "YOUR BASE ID", "updateAllFields": false }, "credentials": { "airtableApi": "Personal Airtable API creds" }, "typeVersion": 1, "alwaysOutputData": true }, { "name": "Prepare clicks count", "type": "n8n-nodes-base.set", "position": [ 1100, 230 ], "parameters": { "values": { "string": [ { "name": "clicks", "value": "={{$node[\"Find by ID1\"].json[\"fields\"][\"clicks\"]+1}}" } ] }, "options": {} }, "typeVersion": 1 }, { "name": "Webhook2", "type": "n8n-nodes-base.webhook", "position": [ 350, 680 ], "webhookId": "8ac18eb4-bcc5-4817-b76d-d93094755ed2", "parameters": { "path": "/dashboard", "options": { "responseHeaders": { "entries": [ { "name": "Content-Type", "value": "text/html" } ] }, "responsePropertyName": "dashboard" }, "responseMode": "lastNode" }, "typeVersion": 1 }, { "name": "Find by ID2", "type": "n8n-nodes-base.airtable", "position": [ 550, 680 ], "parameters": { "table": "YOUR TABLE NAME", "operation": "list", "application": "YOUR BASE ID", "additionalOptions": {} }, "credentials": { "airtableApi": "Personal Airtable API creds" }, "typeVersion": 1, "alwaysOutputData": true }, { "name": "Extract stats", "type": "n8n-nodes-base.function", "position": [ 750, 680 ], "parameters": { "functionCode": "\nitems = items.filter(item=> Object.keys(item.json).length !==0).map(item => item.json.fields);\nif(items.length === 0){\nreturn [{\n json:{\n totalLinks:0,\n totalClick:0,\n totalHosts:0\n }\n}];\n}\nconst totalLinks = items.length;\nconst totalClick = items.map(item => item.clicks).reduce((acc,val) => acc+=val);\nconst hostsMap = new Map();\nconst hosts = items.map(item => item.host);\nhosts.forEach(host => { \n hostsMap.set(host,hostsMap.get(host)!==undefined?hostsMap.get(host)+1:1)\n});\n\nconst totalHosts = [...hostsMap.keys()].length;\n\nreturn [{\n json:{\n totalLinks,\n totalClick,\n totalHosts\n }\n}];" }, "typeVersion": 1 }, { "name": "Set dashboard", "type": "n8n-nodes-base.set", "position": [ 950, 680 ], "parameters": { "values": { "string": [ { "name": "dashboard", "value": "=\n\n\n \n \n \n Dashboard\n\n\n\n\n \n
\n
\n \n n8 \n \n

Dashboard

\n
\n
\n
\n
Total Clicks
\n{{$node[\"Extract stats\"].json[\"totalClick\"]}}\n
\n
\n
Total Links
\n{{$node[\"Extract stats\"].json[\"totalLinks\"]}}\n
\n
\n
Total Hosts
\n{{$node[\"Extract stats\"].json[\"totalHosts\"]}}\n
\n
\n
\n\n" } ] }, "options": {}, "keepOnlySet": true }, "typeVersion": 1 } ], "connections": { "Crypto": { "main": [ [ { "node": "Set ID,shortUrl,longUrl", "type": "main", "index": 0 } ] ] }, "Webhook": { "main": [ [ { "node": "Check URL", "type": "main", "index": 0 } ] ] }, "Airtable": { "main": [ [ { "node": "Set Output1", "type": "main", "index": 0 } ] ] }, "Check Id": { "main": [ [ { "node": "Extract Id", "type": "main", "index": 0 } ], [ { "node": "Set Error output1", "type": "main", "index": 0 } ] ] }, "Webhook1": { "main": [ [ { "node": "Check Id", "type": "main", "index": 0 } ] ] }, "Webhook2": { "main": [ [ { "node": "Find by ID2", "type": "main", "index": 0 } ] ] }, "Check URL": { "main": [ [ { "node": "Extract URL", "type": "main", "index": 0 } ], [ { "node": "Set Error output", "type": "main", "index": 0 } ] ] }, "Set input": { "main": [ [ { "node": "Airtable", "type": "main", "index": 0 } ] ] }, "Extract Id": { "main": [ [ { "node": "Find by ID1", "type": "main", "index": 0 } ] ] }, "Find by ID": { "main": [ [ { "node": "Already exists ?", "type": "main", "index": 0 } ] ] }, "Extract URL": { "main": [ [ { "node": "Crypto", "type": "main", "index": 0 } ] ] }, "Find by ID1": { "main": [ [ { "node": "Already exists ?1", "type": "main", "index": 0 } ] ] }, "Find by ID2": { "main": [ [ { "node": "Extract stats", "type": "main", "index": 0 } ] ] }, "Extract stats": { "main": [ [ { "node": "Set dashboard", "type": "main", "index": 0 } ] ] }, "Update clicks": { "main": [ [ { "node": "Set Output2", "type": "main", "index": 0 } ] ] }, "Already exists ?": { "main": [ [ { "node": "Set Output", "type": "main", "index": 0 } ], [ { "node": "Set input", "type": "main", "index": 0 } ] ] }, "Already exists ?1": { "main": [ [ { "node": "Prepare clicks count", "type": "main", "index": 0 } ], [ { "node": "404 Error", "type": "main", "index": 0 } ] ] }, "Prepare clicks count": { "main": [ [ { "node": "Update clicks", "type": "main", "index": 0 } ] ] }, "Set ID,shortUrl,longUrl": { "main": [ [ { "node": "Find by ID", "type": "main", "index": 0 } ] ] } } }