Python Telegram Bot: Build a Group Management Bot (2026)
Python Telegram Bot: Build a Group Management Bot (2026)
Group management is one of the most practical applications for a custom Telegram bot. A well-built group management bot can welcome new members, enforce rules, kick spammers, restrict flooding, pin announcements, and run polls โ automating the administrative overhead that comes with running a large Telegram group.
In this tutorial you'll build a fully functional group management bot in Python using the python-telegram-bot library. You'll add a welcome message system, anti-spam protection, and member management features. Browse related bots in Developer Tools and Group Management.
Setting Up python-telegram-bot Library
This tutorial uses python-telegram-bot version 21+, which uses asyncio throughout.
pip install "python-telegram-bot[job-queue]"
Create a project structure:
group-bot/
bot.py # Main entry point
handlers.py # Message and command handlers
spam_filter.py # Anti-spam logic
.env # BOT_TOKEN (never commit this)
Install python-dotenv for environment variable loading:
pip install python-dotenv
Building a Welcome Message Bot in Python
The welcome handler fires when new members join the group:
# handlers.py
from telegram import Update, ChatPermissions
from telegram.ext import ContextTypes
import asyncio
# Welcome message configuration
WELCOME_MESSAGE = """
Welcome to the group, {name}! ๐
Please read the rules:
1. Be respectful to all members
2. No spam or self-promotion
3. Stay on topic
Enjoy the community!
"""
async def welcome_new_member(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Greet new members when they join."""
for member in update.message.new_chat_members:
if member.is_bot:
continue # Don't welcome other bots
name = member.mention_html() # @username clickable link
chat_id = update.effective_chat.id
# Send welcome message
msg = await context.bot.send_message(
chat_id=chat_id,
text=WELCOME_MESSAGE.format(name=name),
parse_mode="HTML"
)
# Auto-delete welcome message after 5 minutes
context.job_queue.run_once(
delete_message,
when=300,
data={"chat_id": chat_id, "message_id": msg.message_id}
)
async def delete_message(context: ContextTypes.DEFAULT_TYPE):
"""Delete a message (used for auto-cleanup)."""
job_data = context.job.data
try:
await context.bot.delete_message(
chat_id=job_data["chat_id"],
message_id=job_data["message_id"]
)
except Exception:
pass # Message may already be deleted
Adding Anti-Spam Features
Anti-spam protection is the most critical feature for any group management bot. Here's a multi-layer approach:
# spam_filter.py
from collections import defaultdict
from datetime import datetime, timedelta
from telegram import Update, ChatPermissions
from telegram.ext import ContextTypes
# Track messages per user
message_tracker: dict[int, list[datetime]] = defaultdict(list)
# Config
MAX_MESSAGES = 5 # messages
TIME_WINDOW = 10 # seconds
MUTE_DURATION = 300 # seconds (5 minutes)
async def check_flood(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Mute users who send too many messages in a short window."""
if not update.effective_user or not update.effective_message:
return
user_id = update.effective_user.id
chat_id = update.effective_chat.id
now = datetime.now()
window_start = now - timedelta(seconds=TIME_WINDOW)
# Clean old entries, add current
message_tracker[user_id] = [
t for t in message_tracker[user_id] if t > window_start
]
message_tracker[user_id].append(now)
if len(message_tracker[user_id]) > MAX_MESSAGES:
# Mute the user
until = now + timedelta(seconds=MUTE_DURATION)
try:
await context.bot.restrict_chat_member(
chat_id=chat_id,
user_id=user_id,
permissions=ChatPermissions(can_send_messages=False),
until_date=until
)
await update.effective_message.reply_text(
f"โ ๏ธ {update.effective_user.mention_html()} has been muted "
f"for 5 minutes due to flooding.",
parse_mode="HTML"
)
except Exception as e:
print(f"Could not mute user {user_id}: {e}")
async def check_links(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Delete messages containing Telegram invite links from new members."""
if not update.effective_message or not update.effective_message.text:
return
text = update.effective_message.text
user = update.effective_user
# Check for Telegram invite links
invite_patterns = ["t.me/+", "t.me/joinchat", "telegram.me/joinchat"]
if any(pattern in text for pattern in invite_patterns):
try:
await update.effective_message.delete()
warning = await context.bot.send_message(
chat_id=update.effective_chat.id,
text=f"โ {user.mention_html()}: Invite links are not allowed.",
parse_mode="HTML"
)
# Auto-delete the warning after 30 seconds
context.job_queue.run_once(
lambda ctx: ctx.bot.delete_message(
warning.chat_id, warning.message_id
),
when=30
)
except Exception as e:
print(f"Link filter error: {e}")
Managing Group Members with Python
Admin commands for banning, kicking, and muting specific users:
# admin_handlers.py
from telegram import Update
from telegram.ext import ContextTypes
from telegram.constants import ChatMemberStatus
from functools import wraps
def admin_only(func):
"""Decorator to restrict command to group admins."""
@wraps(func)
async def wrapper(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
chat = update.effective_chat
member = await chat.get_member(user.id)
if member.status not in (
ChatMemberStatus.ADMINISTRATOR,
ChatMemberStatus.OWNER
):
await update.message.reply_text("โ This command is for admins only.")
return
return await func(update, context)
return wrapper
@admin_only
async def ban_user(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Ban replied-to user. Usage: reply to a message with /ban [reason]."""
if not update.message.reply_to_message:
await update.message.reply_text("Reply to a message to ban that user.")
return
target = update.message.reply_to_message.from_user
reason = " ".join(context.args) if context.args else "No reason given"
await context.bot.ban_chat_member(
chat_id=update.effective_chat.id,
user_id=target.id
)
await update.message.reply_text(
f"๐ซ {target.mention_html()} has been banned.\nReason: {reason}",
parse_mode="HTML"
)
@admin_only
async def kick_user(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Kick (remove without ban) replied-to user."""
if not update.message.reply_to_message:
await update.message.reply_text("Reply to a message to kick that user.")
return
target = update.message.reply_to_message.from_user
await context.bot.ban_chat_member(update.effective_chat.id, target.id)
# Immediately unban to allow rejoining
await context.bot.unban_chat_member(update.effective_chat.id, target.id)
await update.message.reply_text(
f"๐ข {target.mention_html()} has been kicked.",
parse_mode="HTML"
)
@admin_only
async def warn_user(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Issue a warning. 3 warnings = auto-ban."""
if not update.message.reply_to_message:
await update.message.reply_text("Reply to a message to warn that user.")
return
target = update.message.reply_to_message.from_user
chat_id = str(update.effective_chat.id)
# Retrieve or initialize warns from bot_data
warns = context.bot_data.setdefault("warns", {})
key = f"{chat_id}:{target.id}"
warns[key] = warns.get(key, 0) + 1
count = warns[key]
if count >= 3:
await context.bot.ban_chat_member(update.effective_chat.id, target.id)
del warns[key]
await update.message.reply_text(
f"๐ซ {target.mention_html()} reached 3 warnings and has been banned.",
parse_mode="HTML"
)
else:
await update.message.reply_text(
f"โ ๏ธ {target.mention_html()} warned. ({count}/3 warnings)",
parse_mode="HTML"
)
Assembling the Bot
# bot.py
import os
from dotenv import load_dotenv
from telegram.ext import (
Application, CommandHandler, MessageHandler,
ChatMemberHandler, filters
)
from handlers import welcome_new_member
from spam_filter import check_flood, check_links
from admin_handlers import ban_user, kick_user, warn_user
load_dotenv()
TOKEN = os.environ["BOT_TOKEN"]
def main():
app = Application.builder().token(TOKEN).build()
# Welcome new members
app.add_handler(MessageHandler(
filters.StatusUpdate.NEW_CHAT_MEMBERS, welcome_new_member
))
# Anti-spam (runs on every text message)
app.add_handler(MessageHandler(filters.TEXT, check_flood), group=1)
app.add_handler(MessageHandler(filters.TEXT, check_links), group=2)
# Admin commands
app.add_handler(CommandHandler("ban", ban_user))
app.add_handler(CommandHandler("kick", kick_user))
app.add_handler(CommandHandler("warn", warn_user))
print("Bot started. Press Ctrl+C to stop.")
app.run_polling(drop_pending_updates=True)
if __name__ == "__main__":
main()
Deploying Your Python Bot
For a VPS (Ubuntu/Debian):
# Install dependencies
sudo apt update && sudo apt install python3 python3-pip -y
pip3 install "python-telegram-bot[job-queue]" python-dotenv
# Create systemd service for auto-restart
sudo nano /etc/systemd/system/telegram-bot.service
[Unit]
Description=Telegram Group Management Bot
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/group-bot
ExecStart=/usr/bin/python3 bot.py
Restart=always
RestartSec=10
EnvironmentFile=/home/ubuntu/group-bot/.env
[Install]
WantedBy=multi-user.target
sudo systemctl enable telegram-bot
sudo systemctl start telegram-bot
sudo systemctl status telegram-bot
FAQ
My bot can't ban or kick users. What's wrong?
The bot must be a group administrator with the "Ban users" permission. Add the bot to your group, then go to Group Settings โ Administrators โ Add Admin โ select your bot โ enable "Ban users" and "Delete messages".
How do I make certain commands admin-only?
Use the @admin_only decorator shown above. It checks the user's role in the chat using get_member() before executing the command handler.
Can the bot work in multiple groups simultaneously?
Yes. Telegram sends updates with the chat.id identifying which group the message came from. The same bot instance handles all groups โ your warning/ban counters just need to be keyed by f"{chat_id}:{user_id}" as shown in the warn handler.
How do I store warns and data persistently across restarts?
python-telegram-bot supports persistence via PicklePersistence: Application.builder().token(TOKEN).persistence(PicklePersistence("bot_data.pkl")).build(). For production, use SQLite or Redis via a custom persistence class.
My bot is deleting messages but missing some. Why?
The bot must receive every message to filter them. Make sure "Privacy Mode" is disabled โ in BotFather, send /mybots โ select your bot โ Bot Settings โ Group Privacy โ Turn off. With privacy mode enabled, the bot only receives messages that start with /.
Share this article