How to Build a Telegram Bot With n8n, and When You Don't Need n8n

A working n8n Telegram bot in six steps, built and tested on n8n 2.42: a menu with inline buttons, a Back button, a team notification and an AI agent with per-chat memory. Then what gets hard, and how to split the work between n8n and a bot builder.

14 min readยทOct 11, 2026
An n8n workflow for a Telegram bot with a trigger, two Switch nodes, menu branches and an AI Agent with memory

We make FlowCastle, a Telegram bot builder, so we are not neutral here. That is why the first half of this page is a plain n8n tutorial with no detour. We built the bot below on n8n 2.42.6 and replayed Telegram messages and button taps through it to check every branch. The screenshots come from that build.

Short answer: n8n builds a simple Telegram bot fast. A trigger, a Switch and a few Telegram nodes give you a menu, buttons and an AI agent. It gets hard when the bot has to hold a conversation: wait for a typed answer, go back one screen, keep a list of the people who wrote. For those, a bot builder is less work, and n8n stays useful behind it.

You can import the finished workflow from a file in Step 6. A FlowCastle template for the same kind of bot is linked at the end.

What you will build

A bot for a small web studio, 14 nodes in total:

  • /start shows a menu with two buttons: Ask a question and Get a quote.
  • Get a quote opens a second menu with three services and a Back button.
  • Picking a service sends a message to the team and confirms to the customer.
  • Any typed question goes to an AI agent that remembers the chat.

What you need, and whether you need a server

  1. A bot token. Open @BotFather in Telegram, send /newbot, pick a name and a username ending in bot. BotFather replies with the token.
  2. An n8n that Telegram can reach over HTTPS. Telegram delivers messages by calling a URL on your n8n, and it only accepts HTTPS. Our local n8n registered http://localhost:5678/webhook/... as that URL. Real Telegram rejects it with Bad Request: bad webhook: An HTTPS URL must be provided for webhook.
  3. A model key for the AI step, for example from OpenAI.

So can you run an n8n Telegram bot without a server? Only on n8n Cloud, where n8n is the server. When we checked in October 2026, the Starter plan was โ‚ฌ20 a month billed annually, with 2,500 executions. Self-hosting has no licence fee, but you need a machine that is always on, a domain, a TLS certificate and the WEBHOOK_URL variable set to your public address. A tunnel such as ngrok works for testing on a laptop.

Step 1: Add the Telegram Trigger

Create a workflow and add a Telegram Trigger node. In Credential, create a new one and paste the token into Access Token.

In Trigger On, choose Message and Callback Query. The second one matters: a button tap does not arrive as a message. It arrives as a callback query, and a trigger that listens only for messages never sees it.

The n8n Telegram Trigger settings with Trigger On set to Message and Callback Query, under a notice that one bot can have only one Telegram trigger at a time

Read the yellow notice too. We come back to it below.

Step 2: Sort what came in

Add a Switch node after the trigger and give it three rules, in this order:

OutputCondition
Button tap{{ $json.callback_query }} exists
/start{{ $json.message.text }} starts with /start
Text{{ $json.message.text }} exists

Keep /start above Text. A /start message matches both rules, and the Switch sends it to the first one that matches. Anything that matches no rule, such as a photo or a sticker, goes nowhere. In our test a photo produced a "successful" execution and no reply at all. Add a fourth output with a polite fallback if that bothers you.

Step 3: Send a menu with inline buttons

Connect the /start output to a Telegram node with the operation Send Message:

  • Chat ID: {{ $json.message.chat.id }}
  • Text: Hi {{ $json.message.from.first_name }}! I'm the Northwind Studio bot. What can I do for you?
  • Reply Markup: Inline Keyboard

Under Inline Keyboard, add a row, then Add Button. Set Text to ๐Ÿ’ฌ Ask a question, open Additional Fields on the button and set Callback Data to ask. Add a second row with ๐Ÿ“‹ Get a quote and callback data quote. The callback data is what your workflow receives when the button is tapped, so keep it short and unique.

The n8n Telegram node set to Send Message with Reply Markup set to Inline Keyboard and a button "Ask a question" whose Callback Data is "ask"

One more setting: in the node's own Additional Fields, turn off Append n8n Attribution. It is on by default and adds a line saying the message was sent with n8n to every message.

Step 4: Handle the button taps

Every tap starts a new run of the workflow. Build this on the Button tap output:

  1. A Telegram node with Resource set to Callback and Operation set to Answer Query. Query ID is {{ $json.callback_query.id }}. Skip this node and the button keeps showing a loading indicator in the customer's app.
  2. A second Switch on {{ $('Telegram Trigger').item.json.callback_query.data }} with four rules: equals ask, equals quote, equals back, starts with svc_.
  3. On each output, a Telegram node with the operation Edit Message Text. Editing replaces the menu in place, which reads better than a new message per tap. Set Chat ID to {{ $('Telegram Trigger').item.json.callback_query.message.chat.id }} and Message ID to {{ $('Telegram Trigger').item.json.callback_query.message.message_id }}.

What each branch shows:

  • quote: "What do you need a quote for?" with the buttons Website (svc_website), Online store (svc_store), Something else (svc_other) and โ† Back (back).
  • back: the main menu again. n8n has no idea what the previous screen was, so this node is a second copy of the text and buttons from Step 3. Change the menu later and you change it in two places.
  • svc_โ€ฆ: first a Send Message to your team's chat ID with the service and the customer's name, then an edit that says "Thanks! We'll message you here within one working day."
  • ask: "Sure. Type your question and I'll answer."

Step 5: Add an AI agent with memory

Connect the Text output of the first Switch to an AI Agent node.

  • Source for Prompt (User Message): Define below
  • Prompt (User Message): {{ $json.message.text }}
  • Options โ†’ System Message: who the bot is and how it should answer.

Attach a chat model, for example OpenAI Chat Model, to the agent's Chat Model port. Then attach Simple Memory to the Memory port:

  • Session ID: Define below
  • Key: {{ $('Telegram Trigger').item.json.message.chat.id }}
  • Context Window Length: 10

The key is what keeps one customer's conversation apart from another's. The default setting takes the session from n8n's own chat trigger, which a Telegram workflow does not have.

The n8n Simple Memory node with Session ID set to Define below, the Telegram chat id as the key, a context window of 10, and a notice that memory is stored locally in the n8n instance

Finish with a Telegram node, Send Message, with the trigger's chat ID and the text {{ $json.output }}.

We checked the memory. A second question from the same chat reached the model together with the first one. A question from another chat arrived alone. Two things to know before you rely on it:

  • Simple Memory lives in n8n's process. We restarted n8n and the agent had forgotten the conversation. The notice in the node says the same, and adds that it does not work in queue mode. For a bot that customers use, swap it for the Postgres or Redis memory node.
  • Formatting. The Telegram node sends with Parse Mode set to HTML by default, and models usually answer in Markdown. Customers then see raw asterisks, and Telegram can refuse a message that contains a stray <. Tell the model in the system message to answer in plain text.

Step 6: Publish and test

Click Publish. n8n registers the webhook with Telegram. Open your bot and send /start.

Each message and each tap is one execution. Our ten test messages and taps made ten executions. On a plan with 2,500 executions a month, that is about 250 short conversations.

To skip the clicking, download the workflow file and use Import from File in the workflow menu. Then pick your own credentials in the Telegram and model nodes.

Where it gets hard

The bot above works. Then someone asks for one more thing: "after they pick a service, ask them to describe the project."

A question that waits for a typed answer

n8n runs every Telegram update on its own. When the customer types "A small shop for handmade candles", nothing in that run says it is the answer to your question. It looks like any other text, so the AI agent answers it.

To fix that you store the state of each conversation yourself. We built it with an n8n data table that has three columns: chat_id, step and service. It took six more nodes: the question itself, and five to track the state:

  • load the row for this chat at the very start;
  • save step = awaiting_brief when the bot asks the question;
  • an If node before the AI agent: is this chat waiting for a brief?
  • clear the step after the answer arrives;
  • reset the step on /start.

The workflow went from 14 nodes to 20 for one question. A second question means a second step value and more branches.

The same n8n workflow after adding one typed question: a data table lookup after the trigger, state writes on three branches, and an If node in front of the AI Agent

Two traps we hit while testing it:

  • A first-time user got no reply. The lookup returns nothing for a chat it has never seen, and n8n stops a branch when a node returns no items. The execution was still marked successful. The fix is Always Output Data in the lookup node's Settings tab.
  • An abandoned form eats the next message. Without the reset on /start, a person who leaves halfway has their next question saved as the "brief".

n8n also has Send and Wait for Response, which pauses a workflow until someone answers. Approval buttons can be answered inside the chat. For a free-text answer, n8n's docs say the person presses a button and types into a web form, not into the Telegram chat. That is fine for an internal approval and awkward for a customer.

The 20-node version is here as a file if you want to study it. Create the data table first and select it in the four data table nodes.

Contacts, tags and broadcasts

n8n does not know who your users are. To message everyone next week, you must have saved every chat ID yourself: another table and another write on every update. Then you loop over the rows, pause between sends because Telegram allows about 30 messages a second for bulk sending, and handle the people who blocked the bot. It can be done. It is a second project.

One webhook per bot

Telegram keeps one webhook address per bot. n8n has a test URL and a production URL, so a bot is either live or being tested, not both. n8n's docs suggest a second bot for testing.

We also published two workflows on the same bot. Both showed as published, only the last one received messages, and unpublishing one of them deleted the bot's webhook, which silences the other. That is the yellow notice from Step 1 in practice.

Keeping it running

If you self-host, the server, the certificate, the updates and the backups are yours. When n8n is down, the bot is silent, and Telegram does not tell your customers why.

The same bot in a bot builder

A bot builder starts from the conversation, so the hard parts above are settings, not nodes. Here is the same Northwind bot in FlowCastle, with the typed question included.

The same bot on the FlowCastle canvas: a start step, the main menu, the services menu with a Back button, the project brief question marked Wait for reply, a team notification, a request to n8n, a confirmation and an AI block that answers questions

Waiting for an answer is a switch. On the message that asks for the brief, turn on Wait for reply and pick a variable under Save reply to variable, here project_brief. There is no state table to build. The details are in Ask Questions and Collect Answers.

The FlowCastle message editor for the project brief question: Wait for reply is on, the expected reply type is Any text, and the reply is saved to the project_brief variable

Back is a checkbox on the button. Open the button's settings and tick Go back. It returns the person to the screen they came from, wherever that was. You do not draw a branch for it, and the menu exists once. The same editor saves the tapped button to a variable, here service, under Store last clicked button in.

The Services menu in the FlowCastle editor with four buttons; the Button Settings popover of the Back button has Go back ticked, and the tapped button is stored in the service variable

Everyone who presses Start becomes a contact. Their answers are saved on the contact, and you can tag people, filter them and send broadcasts without building a table.

The AI block reads stored history. The AI Chat Agent block gets up to the last 40 messages of the chat from the saved conversation, so a restart does not wipe it.

Hosting is included. You paste the token and publish. The Test chat runs the bot in the editor, so you can try a change while the live bot keeps working.

The FlowCastle test chat: the bot shows the menu, Get a quote and Online store are highlighted as tapped, the customer types a short brief and gets a confirmation

On cost, the two are closer than you might expect, because FlowCastle also counts incoming messages and taps. The free plan covers 2,000 of them a month and paid plans start at $9. The difference is the work, not the price.

Keep n8n for what it does well

n8n is better than we are at connecting systems. Its site lists more than 2,000 integrations, and it has schedules, loops and data transformation. FlowCastle does not try to be that.

So split the job. Let the bot hold the conversation, and call n8n once the bot has something worth sending. In FlowCastle, add an External Request step after the brief is saved and point it at a Webhook node in n8n:

POST https://n8n.yourcompany.com/webhook/new-lead

{
  "service": "{{ contact.service }}",
  "project_brief": "{{ contact.project_brief }}"
}

Add the two variables with Insert Variable above the body, so the names are exact. Do not type them by hand.

The FlowCastle External Request editor set to POST with an n8n webhook URL and a JSON body that carries the service and project_brief variables

On the n8n side, the Telegram Trigger, the state table and the keyboards all go away. The workflow starts with a Webhook node and does what n8n is good at: add the lead to the CRM, post to Slack, create a draft invoice. It runs once per lead, not once per tap. It also works the other way: a FlowCastle flow can start from an incoming webhook, so an n8n workflow can trigger it.

When n8n alone is enough

Stay with n8n if:

  • the bot only sends things, such as alerts from your systems to a chat or a channel;
  • one command gives one answer, for example /status;
  • it is an AI chat for you or your team, and you have swapped Simple Memory for a database;
  • you already run n8n and need a menu with a handful of buttons, as in the six steps above.

Reach for a bot builder if the bot asks more than one typed question, has menus more than one level deep, needs a contact list and broadcasts, or will be edited by someone who does not live in n8n.

A longer side-by-side is in FlowCastle vs n8n for Telegram bots. If you have never built a bot before, start with How to Create a Telegram Bot Without Coding.

To try the builder route, install the Telegram Lead Qualification template: a welcome, three questions with buttons, answers saved to the contact and a notification to your team. Change the questions, paste your token and publish.

telegramn8ntutorialai

Frequently asked questions

Can I run an n8n Telegram bot without a server?

Only on n8n Cloud, where n8n hosts the workflow for you. Telegram delivers messages to an HTTPS address, so a self-hosted n8n needs an always-on machine, a domain, a TLS certificate and the WEBHOOK_URL variable. A local n8n on localhost cannot receive Telegram messages without a tunnel.

How do I add buttons to a Telegram bot in n8n?

In the Telegram node choose Send Message, set Reply Markup to Inline Keyboard, add a row and a button, and give the button a Callback Data value. Add Callback Query to the Telegram Trigger, answer each tap with the Answer Query operation, and route on callback_query.data with a Switch node.

Does the n8n AI agent remember the conversation in Telegram?

Yes, if you attach a memory node and set its key to the Telegram chat id. Simple Memory keeps the history inside the n8n process, so it is lost on restart and does not work in queue mode. For a production bot use the Postgres or Redis memory node.

Why does my n8n Telegram bot work in testing but not in production, or the other way round?

Telegram keeps one webhook address per bot. n8n uses one URL for testing and another for the published workflow, so only one of them receives messages at a time. Use a separate bot for testing.

Can I use n8n and FlowCastle together?

Yes. Let the FlowCastle bot hold the conversation and send the result to an n8n Webhook node with an External Request step. n8n then updates your CRM, sheets or other systems.

Try the template

Everything this guide builds is available as a ready-made flow โ€” clone it and adjust instead of starting from scratch.

Don't want to build it yourself? We'll build it for you โ†’