In this tutorial you will build a Telegram bot powered by the Claude API — from BotFather setup to a fully deployed AI assistant that remembers conversation history. Everything runs in Python with python-telegram-bot v20+.
This is a practical telegram bot Python AI guide — by the end you will have a working bot that handles messages, keeps per-user context, and runs as a background service on a VPS.
Prerequisites
- Python 3.10+
- Anthropic API key — get one here
- Telegram account
- VPS (optional, for deployment)
Step 1: Create a Telegram Bot via BotFather
Open Telegram, find @BotFather, send /newbot and follow the prompts. Copy the bot token (format: 7123456789:AAF...).
Step 2: Install Dependencies
pip install python-telegram-bot anthropicStep 3: Basic Echo Bot (Test First)
Before adding Claude, verify your bot token works:
from telegram import Update
from telegram.ext import Application, MessageHandler, filters, ContextTypes
BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = update.message.text
await update.message.reply_text(f"You said: {text}")
app = Application.builder().token(BOT_TOKEN).build()
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
app.run_polling()Send your bot a message in Telegram — it should echo it back. Once it works, move on.
Step 4: Add Claude API
Now replace the echo handler with a Claude-powered one. It keeps per-chat conversation history (last 20 messages) so Claude has context:
from telegram import Update
from telegram.ext import Application, MessageHandler, CommandHandler, filters, ContextTypes
import anthropic
BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
claude = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from env
conversations: dict[int, list] = {}
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
chat_id = update.effective_chat.id
user_text = update.message.text
if chat_id not in conversations:
conversations[chat_id] = []
conversations[chat_id].append({"role": "user", "content": user_text})
history = conversations[chat_id][-20:]
response = claude.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system="You are a helpful assistant. Be concise — this is a Telegram chat.",
messages=history,
)
reply = response.content[0].text
conversations[chat_id].append({"role": "assistant", "content": reply})
await update.message.reply_text(reply)
async def reset_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
conversations.pop(update.effective_chat.id, None)
await update.message.reply_text("Conversation reset.")
app = Application.builder().token(BOT_TOKEN).build()
app.add_handler(CommandHandler("reset", reset_command))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
app.run_polling()The ANTHROPIC_API_KEY is read from environment automatically. See the Claude API Python tutorial for full setup.
Step 5: Add Typing Indicator
Claude takes 1-3 seconds to respond. Show a typing indicator while waiting:
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_chat_action(
chat_id=update.effective_chat.id,
action="typing"
)
# ... rest of the handler unchangedStep 6: Handle Long Responses
Telegram caps messages at 4096 characters. Split long replies:
def split_message(text: str, limit: int = 4000) -> list[str]:
if len(text) <= limit:
return [text]
parts = []
while text:
parts.append(text[:limit])
text = text[limit:]
return parts
# In your handler, replace reply_text with:
for part in split_message(reply):
await update.message.reply_text(part)Step 7: Deploy on a VPS
Run the bot as a persistent systemd service. Create /etc/systemd/system/claude-bot.service:
[Unit]
Description=Claude Telegram Bot
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/claude-bot
ExecStart=/usr/bin/python3 bot.py
Restart=always
Environment=ANTHROPIC_API_KEY=your-key
Environment=BOT_TOKEN=your-token
[Install]
WantedBy=multi-user.targetsudo systemctl enable claude-bot
sudo systemctl start claude-bot
sudo systemctl status claude-botCost Estimate
With 100 daily messages (avg 200 input + 150 output tokens each) using Claude Sonnet:
- Input: ~/usr/bin/zsh.06/day
- Output: ~/usr/bin/zsh.23/day
- Total: ~/month
Add prompt caching on the system prompt to cut input costs by ~90%. See the prompt engineering guide for caching tips.
What to Build Next
/summarizecommand — paste a URL, get a summary- Image analysis — handle
filters.PHOTOand pass to Claude vision - Scheduled reminders — use
job_queuefrom python-telegram-bot - Multi-bot workflows — check n8n + Claude automation for ideas
FAQ
What Python library should I use for Telegram bots?
python-telegram-bot (v20+) is the most popular choice — async, well-documented, actively maintained. aiogram is a good alternative for a lower-level API.
Does the Claude API work with Telegram bots?
Yes. The Anthropic Python SDK works in any async Python context. You call claude.messages.create() inside your Telegram message handler just like in any other Python script.
How much does a Claude-powered Telegram bot cost?
For a personal bot with ~100 messages/day on Claude Sonnet, expect ~$9/month. With prompt caching on the system prompt that drops to under $1/month.
Can I run a Telegram bot without a VPS?
Yes — run_polling() works on your local machine for development. For production, a $4/month VPS or a free-tier cloud function keeps the bot online 24/7.