This workflow corresponds to n8n.io template #3832 — we link there as the canonical source.
This workflow follows the Chat Trigger → Execute Workflow 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "be902a85-fc31-442c-b308-a2350ec5aabb",
"name": "When clicking \u2018Test workflow\u2019",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-960,
368
],
"parameters": {},
"typeVersion": 1
},
{
"id": "d229b686-9de4-4633-9dba-3e1fe71eedf1",
"name": "No Operation, do nothing1",
"type": "n8n-nodes-base.noOp",
"position": [
1824,
800
],
"parameters": {},
"typeVersion": 1
},
{
"id": "3d149fc0-caa7-4361-9bf9-33b6252b39eb",
"name": "get wait seconds",
"type": "n8n-nodes-base.code",
"position": [
-256,
448
],
"parameters": {
"jsCode": "const msg = $json.message || '';\nconst wordCount = msg.split(/\\s+/).filter(w => w).length;\nconst { minWords, waitLong, waitShort } = items[0].json;\nconst waitSeconds = wordCount < minWords ? waitShort : waitLong;\nreturn [{ json: { context_id: $json.context_id, message: msg, waitSeconds } }];\n"
},
"typeVersion": 2
},
{
"id": "cc670735-d126-465f-b0a3-3a4c5e390fd7",
"name": "Set last_seen",
"type": "n8n-nodes-base.redis",
"position": [
288,
384
],
"parameters": {
"key": "=last_seen:{{ $json.context_id}}",
"ttl": "={{ $json.waitSeconds + 60 }}",
"value": "={{$now.toMillis()}}",
"expire": true,
"keyType": "string",
"operation": "set"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "20d97d1d-70d4-4c3c-aa12-b1aa31795240",
"name": "Get waiting_reply",
"type": "n8n-nodes-base.redis",
"position": [
192,
784
],
"parameters": {
"key": "=waiting_reply:{{$json.context_id}}",
"options": {},
"operation": "get",
"propertyName": "waiting_reply"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "7a2fc681-692f-4f72-9fab-f3ada4bda54b",
"name": "Mod input",
"type": "n8n-nodes-base.set",
"position": [
352,
800
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "7ff99444-753d-4ef7-865c-7115761526b8",
"name": "waiting_reply",
"type": "string",
"value": "={{ $json.waiting_reply }}"
},
{
"id": "58ad6981-c35a-4dd6-b1cd-7c446b85e738",
"name": "context_id",
"type": "string",
"value": "={{ $('Config Parameters').item.json.context_id }}"
},
{
"id": "bd0535a2-be03-436b-8a2e-222c3e26fd04",
"name": "message",
"type": "string",
"value": "={{ $('Config Parameters').item.json.message }}"
},
{
"id": "2f583f32-f231-4407-b773-c08b38d464f0",
"name": "waitSeconds",
"type": "number",
"value": "={{ $('get wait seconds').item.json.waitSeconds }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "84213bef-32be-4cd9-8387-cd76aff5cb38",
"name": "waiting_reply?",
"type": "n8n-nodes-base.if",
"position": [
544,
800
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "8136ea21-d798-41fd-81ed-5c0e7fda73c5",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.waiting_reply != null}}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "a8472217-aa83-4247-9d7d-3a471e24478a",
"name": "When chat message received",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
-944,
560
],
"parameters": {
"options": {}
},
"typeVersion": 1.1
},
{
"id": "ba4c81ba-92e2-4bef-a9e2-6f8d4c0aa722",
"name": "Set waiting_reply",
"type": "n8n-nodes-base.redis",
"position": [
848,
720
],
"parameters": {
"key": "=waiting_reply:{{ $json.context_id }}",
"ttl": "={{ $json.waitSeconds }}",
"value": "true",
"expire": true,
"operation": "set"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "0ce783b6-b76b-4a5d-96ae-11708b7532ba",
"name": "Get buffer",
"type": "n8n-nodes-base.redis",
"position": [
1824,
608
],
"parameters": {
"key": "=buffer_in:{{ $('get wait seconds').item.json.context_id }}",
"options": {},
"operation": "get",
"propertyName": "buffer"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "21864061-1d1f-4528-a03f-1237e9c69a31",
"name": "Delete buffer_in",
"type": "n8n-nodes-base.redis",
"position": [
2560,
704
],
"parameters": {
"key": "=buffer_in:{{ $('get wait seconds').item.json.context_id }}",
"operation": "delete"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "8828aa7b-6153-4677-84a8-3ef2f884792c",
"name": "Delete waiting_reply",
"type": "n8n-nodes-base.redis",
"position": [
2560,
864
],
"parameters": {
"key": "=waiting_reply:{{ $('get wait seconds').item.json.context_id }}",
"operation": "delete"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "fc369067-7213-4d8c-b515-c34c4db997e4",
"name": "WaitSeconds",
"type": "n8n-nodes-base.wait",
"position": [
1024,
720
],
"parameters": {
"amount": "={{ $json.waitSeconds }} "
},
"typeVersion": 1.1
},
{
"id": "2daa2ab9-756a-4fdb-8573-b4570c58d6e5",
"name": "Buffer messages",
"type": "n8n-nodes-base.redis",
"position": [
-48,
448
],
"parameters": {
"list": "=buffer_in:{{$json.context_id}}",
"operation": "push",
"messageData": "={{ JSON.stringify({\n\"message\": $json.message,\n\"timestamp\": $now\n}) }}\n"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "4d5bc5f0-11ce-4f7f-b44b-0514a5ab5671",
"name": "Set buffer_count increment",
"type": "n8n-nodes-base.redis",
"position": [
288,
560
],
"parameters": {
"key": "=buffer_count:{{$json.context_id}}",
"expire": "={{$json.waitSeconds + 60}}",
"operation": "incr"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1,
"alwaysOutputData": true
},
{
"id": "dcaee1a8-ea32-4a9d-b32f-f0418644027c",
"name": "Get last_seen",
"type": "n8n-nodes-base.redis",
"position": [
1232,
720
],
"parameters": {
"key": "=last_seen:{{$json.context_id}}",
"options": {},
"operation": "get",
"propertyName": "last_seen"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "908c4a4c-1c60-4e90-827a-064a0b4d6bfd",
"name": "Get buffer_count",
"type": "n8n-nodes-base.redis",
"position": [
1408,
720
],
"parameters": {
"key": "=buffer_count:{{ $('Mod input').item.json.context_id }}",
"options": {},
"operation": "get",
"propertyName": "count"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "1ceb472b-3944-4d74-994b-867ade006e4e",
"name": "Map ouput",
"type": "n8n-nodes-base.set",
"position": [
2752,
512
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "e8d80ab4-74a2-4c30-8500-8dddc5802eec",
"name": "message",
"type": "string",
"value": "={{ $json.message }}"
},
{
"id": "7e7fcee4-14b3-4393-b516-b07a53c018b3",
"name": "context_id",
"type": "string",
"value": "={{$('get wait seconds').item.json.context_id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "0be7e5eb-1972-4a95-b5bf-4e564fc4ef7c",
"name": "Check Inactivity + Count",
"type": "n8n-nodes-base.if",
"position": [
1584,
720
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "or",
"conditions": [
{
"id": "0f294c51-0629-4ae1-a009-68c2f5fd30b5",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{$json.count != null && Number($json.count) >= 3}}",
"rightValue": ""
},
{
"id": "df819099-1f6e-4bee-a017-32b729c836a3",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{($now.toMillis() - $('Get last_seen').item.json.last_seen) >= $('Mod input').item.json.waitSeconds * 1000}}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "0c3bd62b-8cf6-4b34-8010-ebe819db9667",
"name": "Delete waiting_reply1",
"type": "n8n-nodes-base.redis",
"position": [
2560,
1024
],
"parameters": {
"key": "=buffer_count:{{ $('get wait seconds').item.json.context_id }}",
"operation": "delete"
},
"credentials": {
"redis": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "bbf45966-833b-4f5f-ae11-0578614eb156",
"name": "No Operation, do nothing2",
"type": "n8n-nodes-base.noOp",
"position": [
720,
544
],
"parameters": {},
"typeVersion": 1
},
{
"id": "5683eebf-ba51-4a6b-a803-de6acf1b1ea8",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"position": [
2080,
880
],
"parameters": {
"amount": "={{ Math.max(0, Math.ceil(( $('Mod input').item.json.waitSeconds * 1000 - ($now.toMillis() - $('Get last_seen').item.json.last_seen)) / 1000)) }}"
},
"typeVersion": 1.1
},
{
"id": "c0478f60-944e-4c85-bb9c-9abe0d4238c0",
"name": "When Executed by Another Workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"position": [
-688,
640
],
"parameters": {
"workflowInputs": {
"values": [
{
"name": "context_id"
},
{
"name": "message"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "91a650b7-ddd4-4dbf-a300-523f72f0bdb5",
"name": "Mock input data",
"type": "n8n-nodes-base.set",
"position": [
-736,
448
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "0543fdb7-4a22-4530-bdb7-ae7064732fae",
"name": "context_id",
"type": "string",
"value": "={{ $json.sessionId }}"
},
{
"id": "bead5646-a689-4deb-8f4b-b22aa97b51ca",
"name": "message",
"type": "string",
"value": "={{ $json.chatInput || 'Chat 2'}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "cb450e32-7e19-469c-9a5c-3d9da5bf1dfa",
"name": "No Operation, do nothing3",
"type": "n8n-nodes-base.noOp",
"position": [
2944,
864
],
"parameters": {},
"typeVersion": 1
},
{
"id": "b463e405-3355-48a2-a043-42941d7025c3",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
2512,
688
],
"parameters": {
"color": 7,
"width": 700,
"height": 780,
"content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### \ud83e\uddf9 Buffer Cleanup\n\nAfter consolidation and reply:\n\n* **DELETE** keys:\n\n * `buffer_in:{{context_id}}`\n * `buffer_count:{{context_id}}`\n * `waiting_reply:{{context_id}}`\n"
},
"typeVersion": 1
},
{
"id": "1b5397f8-aa7e-4b2b-afb9-5da97d99e049",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-80,
64
],
"parameters": {
"color": 7,
"width": 920,
"height": 940,
"content": "### \ud83d\udce5 Input Buffer\n\n1. **Save incoming message**\n\n * Push the new message into Redis list `buffer_in:{{context_id}}`.\n2. **Update metadata**\n\n * Set `last_seen:{{context_id}}` to the current timestamp (with a TTL of `waitSeconds + 60`).\n * INCR the counter key `buffer_count:{{context_id}}` (also expiring after `waitSeconds + 60`).\n3. **Check \u201cwaiting\u201d flag**\n\n * GET `waiting_reply:{{context_id}}`.\n * If it\u2019s null (no batch in flight), SET it to `true` with TTL `waitSeconds` to block concurrent triggers."
},
"typeVersion": 1
},
{
"id": "edc07500-ccad-4e72-adc1-1a63a3a06609",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1184,
352
],
"parameters": {
"color": 7,
"width": 1200,
"height": 820,
"content": "### \u23f3 Inactivity & Threshold Check\n\n1. **Fetch state**\n\n * GET `last_seen:{{context_id}}` (when the last message arrived)\n * GET `buffer_count:{{context_id}}` (how many messages are queued)\n2. **Evaluate trigger**\n\n * **Inactivity:** `(now \u2013 last_seen) \u2265 waitSeconds * 1000`\n * **Or threshold:** `buffer_count \u2265 1` (or your desired batch size)\n3. **Branch**\n\n * **True:** proceed to \u201cGet buffer\u201d and consolidate.\n * **False:** exit (noOp) and let the waiting\u2010node/flag mechanism retry later."
},
"typeVersion": 1
},
{
"id": "a11187e3-ee43-44bc-8c86-7159ab1ffc87",
"name": "Config Parameters",
"type": "n8n-nodes-base.set",
"position": [
-496,
448
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2f134fe2-203c-4a3b-b3e9-c01bfcbd9405",
"name": "minWords",
"type": "string",
"value": "3"
},
{
"id": "37ec874e-ccf4-4a74-9c7b-0e6f7a6aa73c",
"name": "waitLong",
"type": "string",
"value": "10"
},
{
"id": "2fd93358-5474-401a-99f3-8bd61a23a7ff",
"name": "waitShort",
"type": "string",
"value": "20"
},
{
"id": "b869f5fb-baa0-4b04-9da5-c73f250f5597",
"name": "batchThreshold",
"type": "string",
"value": "3"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "eb1b854e-b514-4e35-b9c3-e5668c31a25d",
"name": "consolidate buffer",
"type": "n8n-nodes-base.code",
"position": [
2160,
704
],
"parameters": {
"jsCode": "// Run Once For All Items\nconst j = items[0].json;\nconst raw = Array.isArray(j.buffer) ? j.buffer : [];\n\n// 1) Parsear cada entrada lo m\u00e1s flexible posible\nconst buffer = raw\n .map(x => {\n let obj;\n // Si viene como string JSON, lo parseo\n if (typeof x === 'string') {\n try {\n obj = JSON.parse(x);\n } catch {\n return null;\n }\n } else if (typeof x === 'object') {\n obj = x;\n } else {\n return null;\n }\n\n // 2) Extraer texto de message, sea string o anidado { text }\n let textVal;\n if (typeof obj.message === 'string') {\n textVal = obj.message;\n } else if (obj.message && typeof obj.message.text === 'string') {\n textVal = obj.message.text;\n } else {\n return null;\n }\n\n // 3) Validar timestamp\n if (!obj.timestamp) return null;\n\n return {\n text: textVal.trim(),\n timestamp: obj.timestamp,\n };\n })\n .filter(Boolean);\n\n// 4) Orden cronol\u00f3gico\nbuffer.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));\n\n// 5) Dedupe y concatenar\nconst unique = [...new Set(buffer.map(m => m.text))];\nconst consolidated = unique.join(' ');\n\n// 6) Devolver\nreturn [{\n json: {\n context_id: j.context_id,\n message: consolidated,\n }\n}];\n"
},
"typeVersion": 2
}
],
"connections": {
"Wait": {
"main": [
[
{
"node": "Check Inactivity + Count",
"type": "main",
"index": 0
}
]
]
},
"Map ouput": {
"main": [
[]
]
},
"Mod input": {
"main": [
[
{
"node": "waiting_reply?",
"type": "main",
"index": 0
}
]
]
},
"Get buffer": {
"main": [
[
{
"node": "consolidate buffer",
"type": "main",
"index": 0
}
]
]
},
"WaitSeconds": {
"main": [
[
{
"node": "Get last_seen",
"type": "main",
"index": 0
}
]
]
},
"Get last_seen": {
"main": [
[
{
"node": "Get buffer_count",
"type": "main",
"index": 0
}
]
]
},
"Set last_seen": {
"main": [
[
{
"node": "No Operation, do nothing2",
"type": "main",
"index": 0
}
]
]
},
"waiting_reply?": {
"main": [
[
{
"node": "No Operation, do nothing2",
"type": "main",
"index": 0
}
],
[
{
"node": "Set waiting_reply",
"type": "main",
"index": 0
}
]
]
},
"Buffer messages": {
"main": [
[
{
"node": "Set buffer_count increment",
"type": "main",
"index": 0
},
{
"node": "Set last_seen",
"type": "main",
"index": 0
},
{
"node": "Get waiting_reply",
"type": "main",
"index": 0
}
]
]
},
"Mock input data": {
"main": [
[
{
"node": "Config Parameters",
"type": "main",
"index": 0
}
]
]
},
"Delete buffer_in": {
"main": [
[
{
"node": "No Operation, do nothing3",
"type": "main",
"index": 0
}
]
]
},
"Get buffer_count": {
"main": [
[
{
"node": "Check Inactivity + Count",
"type": "main",
"index": 0
}
]
]
},
"get wait seconds": {
"main": [
[
{
"node": "Buffer messages",
"type": "main",
"index": 0
}
]
]
},
"Config Parameters": {
"main": [
[
{
"node": "get wait seconds",
"type": "main",
"index": 0
}
]
]
},
"Get waiting_reply": {
"main": [
[
{
"node": "Mod input",
"type": "main",
"index": 0
}
]
]
},
"Set waiting_reply": {
"main": [
[
{
"node": "WaitSeconds",
"type": "main",
"index": 0
}
]
]
},
"consolidate buffer": {
"main": [
[
{
"node": "Map ouput",
"type": "main",
"index": 0
},
{
"node": "Delete buffer_in",
"type": "main",
"index": 0
},
{
"node": "Delete waiting_reply",
"type": "main",
"index": 0
},
{
"node": "Delete waiting_reply1",
"type": "main",
"index": 0
}
]
]
},
"Delete waiting_reply": {
"main": [
[
{
"node": "No Operation, do nothing3",
"type": "main",
"index": 0
}
]
]
},
"Delete waiting_reply1": {
"main": [
[
{
"node": "No Operation, do nothing3",
"type": "main",
"index": 0
}
]
]
},
"Check Inactivity + Count": {
"main": [
[
{
"node": "Get buffer",
"type": "main",
"index": 0
}
],
[
{
"node": "No Operation, do nothing1",
"type": "main",
"index": 0
}
]
]
},
"No Operation, do nothing1": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Set buffer_count increment": {
"main": [
[
{
"node": "No Operation, do nothing2",
"type": "main",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "Mock input data",
"type": "main",
"index": 0
}
]
]
},
"When Executed by Another Workflow": {
"main": [
[
{
"node": "Config Parameters",
"type": "main",
"index": 0
}
]
]
},
"When clicking \u2018Test workflow\u2019": {
"main": [
[
{
"node": "Mock input data",
"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.
redis
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow implements a lightweight message-batching buffer using Redis for temporary storage and a JavaScript consolidation function to merge messages. It collects incoming user messages per session, waits for a configurable inactivity window or batch size threshold,…
Source: https://n8n.io/workflows/3832/ — 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 workflow is built for creators, solopreneurs, SaaS founders, and agencies looking to automate their social media content process from idea to publication. It combines the power of OpenAI, Google
✨🩷Automated Social Media Content Publishing Factory + System Prompt Composition. Uses chatTrigger, stickyNote, toolWorkflow, memoryBufferWindow. Chat trigger; 100 nodes.
This workflow is designed for content creators, social media managers, and marketing teams who need to efficiently create and publish content across multiple social media platforms. It's perfect for b
This workflow is ideal for individuals, marketers, agencies, and brands who want to effortlessly automate the entire blogging and social media process—from idea generation to promotion. Its primary go
✨🩷Automated Social Media Content Publishing Factory + System Prompt Composition. Uses chatTrigger, stickyNote, toolWorkflow, memoryBufferWindow. Chat trigger; 56 nodes.