🤖 Build a Telegram Bot with Python
Want to build your own Telegram bot from scratch? In this guide we go from zero to a fully working bot using Python and VS Code — no experience needed. The tutorial is split into two levels: Level 1 covers complete setup and your first bot that greets users by name. Level 2 adds commands like /start and /help for smarter responses.
🛠️ What You Need
🔑 Get Your Bot Token from BotFather
Every Telegram bot needs a token — think of it as a unique password that connects your Python code to your bot on Telegram. You get this token from BotFather, an official Telegram bot that manages all bots.
- Open Telegram and search for @BotFather, then start a chat
- Send the command:
/newbot - It will ask for a display name — type anything, e.g.
My First Bot - Then it asks for a username — must end in
bot, e.g.myfirsttest_bot - BotFather replies with your token, which looks like this:
7123456789:AAHxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Copy it and save it somewhere — you will need it in your code.
📁 Set Up Your Project in VS Code
- Create a new folder anywhere on your PC — name it something like
telegram_bot - Open VS Code → File → Open Folder → select that folder
- In the Explorer panel on the left, click the New File icon and name the file
bot.py - Press
Ctrl + `to open the terminal at the bottom of VS Code
Your workspace is ready. No extra commands needed.
⚙️ Install the Library
We use the python-telegram-bot library — it handles all the communication with Telegram's servers so you don't have to. In the VS Code terminal, run:
pip install python-telegram-bot
Wait for it to finish. You will see Successfully installed at the end when it is done.
async/await style. If you already have an older version, update it with: pip install python-telegram-bot --upgrade
💻 Level 1 Code — Name Greeting Bot
This is the simplest possible bot. The user types their name, and the bot replies with "Hello [name]! 👋". Paste this into your bot.py file:
from telegram import Update
from telegram.ext import ApplicationBuilder, MessageHandler, filters, ContextTypes
TOKEN = "YOUR_BOT_TOKEN_HERE" # paste your token here
async def reply_hello(update: Update, context: ContextTypes.DEFAULT_TYPE):
name = update.message.text # reads whatever the user typed
await update.message.reply_text(f"Hello {name}! 👋")
app = ApplicationBuilder().token(TOKEN).build()
app.add_handler(MessageHandler(filters.TEXT, reply_hello))
print("Bot is running...")
app.run_polling()
Replace "YOUR_BOT_TOKEN_HERE" with the actual token you copied from BotFather.
What each part does:
TOKEN— your bot's identity, connects the code to Telegramasync def reply_hello— a function that runs every time a message is receivedupdate.message.text— reads what the user typedreply_text(f"Hello {name}!")— sends the reply back using that textMessageHandler(filters.TEXT, reply_hello)— for any text message, callreply_hellorun_polling()— keeps the bot alive and listening for new messages
▶️ Run and Test the Bot
In the VS Code terminal, run:
python bot.py
You will see:
Bot is running...
Now open Telegram, search for your bot by its username (e.g. @myfirsttest_bot), and send it a message:
You: Harsh
Bot: Hello Harsh! 👋
Ctrl + C.
🆕 What's New in Level 2
In Level 1, the bot replied to every single message the same way. In Level 2, we add commands — special messages that start with / — and make the bot behave differently based on what the user sends.
/start— sends a welcome message when the user first opens the bot/help— shows a list of all available commands/hello— greets the user using their actual Telegram profile name- Any plain text — still does the name greeting from Level 1
💻 Level 2 Code — Commands Bot
Replace everything in your bot.py with this:
from telegram import Update
from telegram.ext import (
ApplicationBuilder, CommandHandler,
MessageHandler, filters, ContextTypes
)
TOKEN = "YOUR_BOT_TOKEN_HERE"
# Runs when user sends /start
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(
"👋 Hi! I'm your bot.\n"
"Send me your name and I'll greet you.\n"
"Or type /help to see all commands."
)
# Runs when user sends /help
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(
"📋 Commands:\n"
"/start — Welcome message\n"
"/help — This list\n"
"/hello — Bot greets you by your Telegram name\n\n"
"Or just type any name and I'll say hello!"
)
# Runs when user sends /hello — uses their Telegram profile name
async def hello_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
name = update.effective_user.first_name # reads from their Telegram profile
await update.message.reply_text(f"Hello, {name}! 😊")
# Runs for any plain text message (not a /command)
async def reply_hello(update: Update, context: ContextTypes.DEFAULT_TYPE):
name = update.message.text # reads what the user typed
await update.message.reply_text(f"Hello {name}! 👋")
app = ApplicationBuilder().token(TOKEN).build()
# Register command handlers
app.add_handler(CommandHandler("start", start))
app.add_handler(CommandHandler("help", help_command))
app.add_handler(CommandHandler("hello", hello_command))
# Text handler — fires only for plain messages, not /commands
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, reply_hello))
print("Bot is running...")
app.run_polling()
Key differences from Level 1:
CommandHandler("start", start)— handles/startspecifically, not all messagesupdate.effective_user.first_name— reads the name from their Telegram profile (used in/hello)update.message.text— reads what they actually typed (used in plain text replies)~filters.COMMAND— the~means "not a command", so the text handler only fires for normal messages
📊 Expected Output
Run python bot.py again and test all the commands in Telegram. Here is what each one does:
You: /start
Bot: 👋 Hi! I'm your bot.
Send me your name and I'll greet you.
Or type /help to see all commands.
You: /help
Bot: 📋 Commands:
/start — Welcome message
/help — This list
/hello — Bot greets you by your Telegram name
Or just type any name and I'll say hello!
You: /hello
Bot: Hello, Harsh! 😊
You: Harsh
Bot: Hello Harsh! 👋
➕ Adding More Commands — The Pattern
Every new command follows the same 3-step pattern. Here is an example — a /joke command:
# Step 1 — define the function
async def joke(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Why do programmers hate nature? Too many bugs! 🐛")
# Step 2 — register it (add this before app.run_polling)
app.add_handler(CommandHandler("joke", joke))
# Step 3 — user types /joke in Telegram and gets the reply
That is all there is to it. Define a function → register it → it works.
🚀 Next Steps
Now that your bot is working, here is what you can build next: connect it to a weather API to create a weather bot, add a database to remember users, use inline keyboards for button-based menus, or deploy it to a free cloud host like Railway or PythonAnywhere so it runs 24/7 without keeping your computer on. Happy building!
