This workflow corresponds to n8n.io template #7834 — we link there as the canonical source.
This workflow follows the Agent → Google Sheets 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": "fM5PRDQlmoaAlnBm",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Agent Rate Limiter",
"tags": [
{
"id": "2GEineegHgFbbJ26",
"name": "AI",
"createdAt": "2025-08-04T12:39:26.962Z",
"updatedAt": "2025-08-04T12:39:26.962Z"
},
{
"id": "ewcMZyQBnLVMPImC",
"name": "AI Agent",
"createdAt": "2025-08-04T12:39:26.852Z",
"updatedAt": "2025-08-04T12:39:26.852Z"
}
],
"nodes": [
{
"id": "6d351c55-6aad-4031-8456-0ea676d390b9",
"name": "Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-880,
464
],
"parameters": {
"text": "={{ $('Telegram').item.json.message.text }}",
"options": {
"systemMessage": "=You are a knowledgeable and helpful AI assistant designed to provide accurate, thoughtful, and actionable responses. Your role is to:\n\nCORE PRINCIPLES:\n- Provide clear, accurate information based on your knowledge\n- Admit uncertainty when you don't know something\n- Ask clarifying questions when requests are ambiguous\n- Prioritize user safety and well-being in all responses\n- Maintain a professional yet friendly tone\n\nRESPONSE GUIDELINES:\n- Structure longer responses with clear headings or bullet points\n- Provide step-by-step instructions for complex tasks\n- Include relevant examples when helpful\n- Suggest follow-up actions or resources when appropriate\n- Keep responses concise but comprehensive\n\nLIMITATIONS AWARENESS:\n- Acknowledge when tasks require real-time information you cannot access\n- Explain if requests fall outside your capabilities\n- Recommend human experts or specialized tools when appropriate\n\nRemember: Users have limited messages per session, so make each response valuable and complete. Focus on giving thorough, actionable help that addresses their needs efficiently."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.7
},
{
"id": "eb0afcd5-fcdb-4718-99e9-47fb932a7ae4",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
-1456,
432
],
"parameters": {
"jsCode": "// Get the data from the lookup result\nconst currentRow = $input.first().json;\n\n// Get current message count from column B (if it doesn't exist, start at 0)\nconst currentCount = $input.first().json['Message Counter'] || 0;\n\n// Add 1 to the count\nconst newCount = parseInt(currentCount) + 1;\n\n// Return the data we need for the next step\nreturn {\n json: {\n session_id: currentRow.A,\n message_count: newCount,\n row_number: currentRow.__rowNum\n }\n};"
},
"typeVersion": 2
},
{
"id": "334982a1-5681-4718-ac94-51d1ffe80bd4",
"name": "Append or update row in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1792,
432
],
"parameters": {
"columns": {
"value": {
" ID": "={{ $json.message.chat.id }}"
},
"schema": [
{
"id": " ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": " ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Message Counter",
"type": "string",
"display": true,
"required": false,
"displayName": "Message Counter",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
" ID"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
"cachedResultName": "Message Counter"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "94d0cedf-8dc7-4f6a-905f-b8312a060f2b",
"name": "Get row(s) in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1616,
432
],
"parameters": {
"options": {
"dataLocationOnSheet": {
"values": {
"range": "A:Z",
"rangeDefinition": "specifyRangeA1"
}
}
},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $('Telegram').item.json.message.chat.id }}",
"lookupColumn": " ID"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
"cachedResultName": "Message Counter"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "35755fa3-22db-4457-a54e-6b35cc3d0b8a",
"name": "Append or update row in sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1280,
432
],
"parameters": {
"columns": {
"value": {
" ID": "={{ $('Telegram').item.json.message.chat.id }}",
"Message Counter": "={{ $json.message_count }}"
},
"schema": [
{
"id": " ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": " ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Message Counter",
"type": "string",
"display": true,
"required": false,
"displayName": "Message Counter",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
" ID"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
"cachedResultName": "Message Counter"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.6
},
{
"id": "012468ea-8550-40c1-a66c-10de42cc97f0",
"name": "Azure",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
-880,
640
],
"parameters": {
"model": "gpt-4.1-2",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "2374ffee-2bbc-4d99-9b01-cd8c44510e43",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1504,
896
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "7c7712f0-3fce-4be9-a5ab-e3266e7c8d78",
"name": "Get row(s) in sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1504,
1040
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
"cachedResultName": "Message Counter"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "b33dba91-644e-4a8e-b92e-24858e290561",
"name": "Update row in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-1504,
1200
],
"parameters": {
"columns": {
"value": {
" ID": "={{ $json[' ID'] }}",
"Message Counter": "0"
},
"schema": [
{
"id": " ID",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": " ID",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Message Counter",
"type": "string",
"display": true,
"required": false,
"displayName": "Message Counter",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
" ID"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hBZwpnCr_PZeiALke7ifgBjaUiPWS8Ml6zbbafQbavY/edit?usp=drivesdk",
"cachedResultName": "Message Counter"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "0a292f78-fd84-4b0f-9880-c0d84049a93f",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2032,
832
],
"parameters": {
"color": 3,
"width": 720,
"height": 528,
"content": "## \ud83d\udd04 Automatic Reset System (Separate Workflow Branch)\n\n### Reset Schedule Options:\n- **Current:** Every 1 minute (for testing)\n- **Hourly:** Change to `0 * * * *`\n- **Daily:** Change to `0 0 * * *` (midnight)\n- **Weekly:** Change to `0 0 * * 0` (Sunday)\n- **Custom:** Any cron expression\n\n### Reset Process:\n1. **Schedule Trigger** fires at set intervals\n2. **Get all user records** from Google Sheets\n3. **Bulk reset all counters** to 0\n4. **Users can interact again** after reset\n\n### Configuration Tips:\n- **Testing:** Use minutes for quick testing\n- **Production:** Use hourly/daily for real deployment\n- **High Traffic:** Consider shorter intervals\n- **Cost Control:** Use longer intervals\n\n"
},
"typeVersion": 1
},
{
"id": "0533d580-8ce6-43b4-86a1-5f399b254829",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
-1104,
416
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e34ecf3a-c51e-4cb3-9014-bfba185797f9",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json['Message Counter'] }}",
"rightValue": 3
}
]
}
},
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c0a45d11-2dc9-4022-838d-677e77096020",
"operator": {
"type": "number",
"operation": "equals"
},
"leftValue": "={{ $json['Message Counter'] }}",
"rightValue": 3
}
]
}
},
{
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e6dc0f88-a9b6-417b-917e-904ebbbeff2c",
"operator": {
"type": "number",
"operation": "lt"
},
"leftValue": "={{ $json['Message Counter'] }}",
"rightValue": 3
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "04b0a71c-ac0f-4781-a836-513fbc8658d5",
"name": "No Operation",
"type": "n8n-nodes-base.noOp",
"position": [
-576,
208
],
"parameters": {},
"typeVersion": 1
},
{
"id": "7287f221-93fa-4ffe-96d4-e173b73a0554",
"name": "Limit Message",
"type": "n8n-nodes-base.telegram",
"position": [
-576,
352
],
"parameters": {
"text": "=Daily limit exceeded \ud83d\udeab. Try again later \u23f3. ",
"chatId": "={{ $('Telegram').item.json.message.chat.id }}",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "a5c77b19-ee2f-46d0-afb8-bd37269611e8",
"name": "Agent Answer",
"type": "n8n-nodes-base.telegram",
"position": [
-576,
512
],
"parameters": {
"text": "={{ $json.output }}",
"chatId": "={{ $('Telegram').item.json.message.chat.id }}",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "9f24f7b1-2971-4142-a5c7-99e6fbda7e17",
"name": "Telegram",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-1968,
432
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "f6ca6972-3c8e-4f05-b215-955786367b52",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2736,
-128
],
"parameters": {
"color": 5,
"width": 656,
"height": 912,
"content": "## \ud83e\udd16 AI Agent Rate Limiter\n\n### What does this workflow do?\nThis template solves a critical production problem: **controlling AI agent usage to prevent abuse and manage costs** when deploying chatbots publicly.\n\n### Key Features:\n- **Per-user message limits** (default: 3 messages)\n- **Automatic counter resets** (configurable intervals)\n- **User-friendly limit notifications**\n- **Google Sheets tracking system**\n\n### Perfect for:\n- Customer service bots with quotas\n- Demo/trial AI assistants\n- Educational chatbots with daily limits\n- Cost-controlled production deployments\n\n### Quick Start:\n1. Set up your Telegram bot\n2. Create Google Sheets for tracking\n3. Configure your AI model \n4. Adjust message limits in Switch node\n5. Set reset schedule frequency\n6. Deploy and monitor usage!\n\n## \ud83d\udee0\ufe0f Easy Customization\n\n### Google Sheets Setup:\n1. Create new spreadsheet\n2. Add headers: \"ID\" (Column A), \"Message Counter\" (Column B)\n3. **Switch Node:** Modify conditions (3 \u2192 your limit)\n4. **All Routes:** Update comparison values\n5. **Schedule Trigger:** Change interval settings\n6. **Custom Limit Messages:** Edit Telegram nodes\n\n"
},
"typeVersion": 1
},
{
"id": "a674ef45-ee99-4625-ab47-789a0b2dc32c",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2032,
-128
],
"parameters": {
"color": 4,
"width": 1680,
"height": 912,
"content": "## \ud83d\udcca Smart Message Tracking\n\n### How it works:\n1. **User sends message** \u2192 Telegram Trigger\n2. **Create/Update user record** in Google Sheets\n3. **Lookup current count** for this user\n4. **Increment counter** by 1\n5. **Check against limits** using Switch node\n\n### Google Sheets Structure:\n- **Column A:** User ID (Telegram chat.id)\n- **Column B:** Message Counter (current count)\n\n### Switch Logic:\n- **Route 1:** > 3 messages \u2192 Block (No Operation)\n- **Route 2:** = 3 messages \u2192 Send limit warning\n- **Route 3:** < 3 messages \u2192 Allow AI response\n\n**Tip:** Easily change the limit by modifying the Switch node conditions!"
},
"typeVersion": 1
},
{
"id": "fae65b4d-9afa-432f-95f9-719d578eff33",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-944,
-128
],
"parameters": {
"width": 592,
"height": 912,
"content": "## \ud83d\udcac User-Friendly Responses\n\n### Three Response Types:\n\n**1. Normal AI Response**\n- When user is within limits\n- Full AI capabilities active\n- Conversation memory maintained\n\n**2. Limit Warning Message**\n- \"You've hit the limit, try after!\"\n- Sent when exactly at limit\n- Customizable message text\n\n**3. Silent Block**\n- No response when over limit\n- Prevents spam/abuse\n- User must wait for reset\n"
},
"typeVersion": 1
},
{
"id": "d90f5c67-c8a2-43df-bbd9-d727788c59b9",
"name": "Memory",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-784,
640
],
"parameters": {
"sessionKey": "={{ $('Telegram').item.json.message.chat.id }}",
"sessionIdType": "customKey"
},
"typeVersion": 1.3
}
],
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "d84fb1e2-3d76-4eb6-b175-a8c6dab6daeb",
"connections": {
"Code": {
"main": [
[
{
"node": "Append or update row in sheet1",
"type": "main",
"index": 0
}
]
]
},
"Agent": {
"main": [
[
{
"node": "Agent Answer",
"type": "main",
"index": 0
}
]
]
},
"Azure": {
"ai_languageModel": [
[
{
"node": "Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Memory": {
"ai_memory": [
[
{
"node": "Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "No Operation",
"type": "main",
"index": 0
}
],
[
{
"node": "Limit Message",
"type": "main",
"index": 0
}
],
[
{
"node": "Agent",
"type": "main",
"index": 0
}
]
]
},
"Telegram": {
"main": [
[
{
"node": "Append or update row in sheet",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get row(s) in sheet1",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet1": {
"main": [
[
{
"node": "Update row in sheet",
"type": "main",
"index": 0
}
]
]
},
"Append or update row in sheet": {
"main": [
[
{
"node": "Get row(s) in sheet",
"type": "main",
"index": 0
}
]
]
},
"Append or update row in sheet1": {
"main": [
[
{
"node": "Switch",
"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.
azureOpenAiApigoogleSheetsOAuth2ApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Production-ready solution for controlling AI agent usage and preventing abuse while managing costs.
Source: https://n8n.io/workflows/7834/ — 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.
Template Name: AI Personal Assistant - Task & Email Management Price: $27 Category: Productivity & Automation Difficulty: Intermediate Use Case: Personal productivity automation for busy professionals
This workflow contains community nodes that are only compatible with the self-hosted version of n8n. In simple terms, this workflow triggers when you receive an e-mail in your inbox; classifies this e
This workflow manages subscription billing reminders and data updates via Telegram. It runs daily at 8:00 AM to check for upcoming due subscriptions, formats relevant information, and sends reminders
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
BoomerBobBot.TP. Uses agent, telegramTrigger, telegram, memoryBufferWindow. Event-driven trigger; 95 nodes.