Skip to main content
This example creates a simple agent for answering questions on Telegram:
from agno.agent import Agent
from agno.models.google import Gemini
from agno.os.app import AgentOS
from agno.os.interfaces.telegram import Telegram

telegram_agent = Agent(
    name="Telegram Bot",
    model=Gemini(id="gemini-2.5-pro"), # Ensure GOOGLE_API_KEY is set
    add_history_to_context=True,
    num_history_runs=3,
    add_datetime_to_context=True,
    markdown=True,
)

agent_os = AgentOS(
    agents=[telegram_agent],
    interfaces=[Telegram(agent=telegram_agent)],
)
app = agent_os.get_app()

if __name__ == "__main__":
    agent_os.serve(app="telegram_bot:app", port=7777, reload=True)
Install the dependency: uv pip install 'agno[telegram]'
Each Telegram chat gets its own session scope (e.g., tg:Telegram Bot:123456789), so conversations stay isolated across chats.

Built-in Commands

The Telegram interface registers three commands automatically:
CommandDefault BehaviorCustomization Parameter
/startSends a welcome messagestart_message
/helpLists supported input typeshelp_message
/newStarts a fresh conversation (requires a database)new_message
Commands are registered with the Telegram Bot API on first message when register_commands=True (default).

Key Features

FeatureDetails
StreamingEdits the response message in real time as tokens arrive. Throttled to ~1 edit/sec for rate limits. Enable with streaming=True (default).
Media inputAccepts photos, voice notes, audio, video, video notes, stickers, GIFs, and documents. Media is downloaded and passed to the agent automatically.
Media outputAgent tools (e.g., DALL-E, ElevenLabs) can send photos, audio, video, documents, GIFs, and stickers as native Telegram media.
Message chunkingResponses longer than 4096 characters are automatically split across multiple messages.
Show reasoningSet show_reasoning=True to surface the model’s reasoning as a blockquote message.

Local Development Setup

1

Prerequisites

Ensure you have the following:
  • A Telegram account
  • ngrok (for development)
  • Python 3.7+
2

Create a Telegram Bot

  1. Open Telegram and message @BotFather
  2. Send /newbot and follow the prompts to choose a display name and username (username must end in bot, e.g. my_agno_bot)
  3. Copy the bot token (looks like 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
3

Set Environment Variables

export TELEGRAM_TOKEN="your-bot-token-from-botfather"
export APP_ENV="development"  # Bypasses webhook secret validation for local testing
4

Start a Tunnel with ngrok

Telegram needs a public HTTPS URL to deliver webhook events:
ngrok http 7777
# Or, if you have a paid ngrok plan with a static domain:
# ngrok http --domain=your-custom-domain.ngrok-free.app 7777
Copy the https:// forwarding URL provided by ngrok and set it as an environment variable:
export NGROK_URL=https://your-subdomain.ngrok-free.app
5

Run the App

python telegram_bot.py
The server starts on http://localhost:7777.
6

Register the Webhook

Tell Telegram to send updates to your tunnel URL:
curl "https://api.telegram.org/bot${TELEGRAM_TOKEN}/setWebhook?url=${NGROK_URL}/telegram/webhook"
You should see {"ok":true,"result":true,"description":"Webhook was set"}.Verify anytime with:
curl "https://api.telegram.org/bot${TELEGRAM_TOKEN}/getWebhookInfo"

Production Deployment

In production, webhook secret validation is enforced. Telegram sends the secret in the X-Telegram-Bot-Api-Secret-Token header, and the interface rejects requests with an invalid or missing token with a 403.
1

Set the Webhook Secret

Generate a secret and set it as an environment variable:
export TELEGRAM_WEBHOOK_SECRET_TOKEN="your-random-secret-string"
2

Register the Webhook with the Secret

Pass the secret_token parameter when registering your webhook:
curl "https://api.telegram.org/bot${TELEGRAM_TOKEN}/setWebhook?url=https://your-domain.com/telegram/webhook&secret_token=${TELEGRAM_WEBHOOK_SECRET_TOKEN}"
3

Remove APP_ENV=development

Do not set APP_ENV=development in production. Without it, webhook secret validation is active.

Group Chat Setup

By default, Telegram bots in groups only receive commands (/start, etc.), @mentions, and replies to their own messages. To allow the bot to read all group messages:
1

Disable Privacy Mode in BotFather

  1. Open a chat with @BotFather
  2. Send /mybots and select your bot
  3. Go to Bot SettingsGroup Privacy
  4. Tap Turn off
BotFather confirms: “Privacy mode is disabled for YourBot.”
2

Re-add the Bot to Existing Groups

Privacy mode changes only apply to groups the bot joins after the change. Remove and re-add the bot to any existing groups. Alternatively, making the bot a group admin bypasses privacy mode entirely.
3

Configure Reply Behavior

Control whether the bot responds to every message or only mentions:
Telegram(
    agent=telegram_agent,
    reply_to_mentions_only=True,   # True (default): respond to @mentions and direct replies only
    reply_to_bot_messages=True,    # True (default): also respond when users reply to the bot's messages
)
Set reply_to_mentions_only=False to respond to all messages in the group.

Troubleshooting

ProblemCauseFix
403 Forbidden on webhookMissing or invalid webhook secretSet TELEGRAM_WEBHOOK_SECRET_TOKEN and register the webhook with a matching secret_token, or set APP_ENV=development for local testing
Bot doesn’t respond in groupsPrivacy mode enabledDisable privacy mode in BotFather and re-add the bot to the group
Bot doesn’t respond at allWebhook not registered or server not runningVerify with getWebhookInfo and check that your server is reachable
Streaming not workingstreaming set to FalseSet streaming=True on the Telegram interface (this is the default)

Developer Resources