Telegram bots are simple to start and easy to get wrong in production. The defining decision — more than the framework or language — is polling vs webhooks, because it determines whether you deploy a long-running worker or a web service. This guide uses the popular [python-telegram-bot](https://python-telegram-bot.org) library and covers both modes honestly.
Polling vs webhooks
Telegram delivers updates (messages, button presses) two ways:
| Mode | How updates arrive | Hosting shape | Public port |
|---|---|---|---|
| Long polling | Bot repeatedly asks Telegram for updates | long-running worker | no |
| Webhook | Telegram POSTs updates to your HTTPS URL | web service | yes (HTTPS) |
Polling is dead simple: the bot continuously calls getUpdates. No public URL, no SSL setup — just a process that runs forever. It's perfect for getting started and for low-to-medium traffic. The cost is a process that's always awake making requests.
Webhooks are more efficient at scale: Telegram pushes updates to your endpoint, so there's no polling loop. But webhooks require a public HTTPS URL with a valid certificate — Telegram refuses plain HTTP. This makes webhooks a natural fit for a web service (or even an edge function) where SSL is handled for you.
Polling bot (worker)
import os
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes
async def start(update: Update, ctx: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text("Hello!")
app = Application.builder().token(os.environ["BOT_TOKEN"]).build()
app.add_handler(CommandHandler("start", start))
app.run_polling()Deploy this as an always-on worker with no public port. It must not scale to zero — a sleeping poller stops responding. Inject BOT_TOKEN (from [@BotFather](https://t.me/botfather)) as a secret.
Webhook bot (web service)
import os
from telegram.ext import Application, CommandHandler
app = Application.builder().token(os.environ["BOT_TOKEN"]).build()
app.add_handler(CommandHandler("start", start))
app.run_webhook(
listen="0.0.0.0",
port=int(os.environ["PORT"]),
url_path=os.environ["BOT_TOKEN"],
webhook_url=f"https://yourbot.yourdomain.com/{os.environ['BOT_TOKEN']}",
)Here the bot binds to $PORT and Telegram delivers to your HTTPS domain. Deploy this as a web service. PandaStack issues automatic SSL on your custom domain, which satisfies Telegram's HTTPS requirement without you touching certificates. Using the token as the URL path is a simple way to keep the webhook endpoint secret; for extra safety, set a secret_token so you can verify Telegram is the caller.
Which should you choose?
- Start with polling. It's simpler, needs no domain, and is fine for most bots.
- Move to webhooks when you want lower latency, lower idle cost, or are running multiple replicas. Note: you cannot run multiple polling instances of the same bot — Telegram will error. Webhooks are the path to horizontal scaling.
Persisting state
python-telegram-bot keeps conversation state in memory by default, which evaporates on restart. For anything stateful — multi-step conversations, user preferences, scheduled reminders — back it with a database. Attach a managed PostgreSQL and use the auto-wired DATABASE_URL (with asyncpg or psycopg), or use the library's persistence interface. For reminders and broadcasts, a cronjob that runs a script is more reliable than an in-process job queue that dies with the bot.
Security notes
- Treat
BOT_TOKENas a password; regenerate via BotFather if it leaks. - For webhooks, set and verify a
secret_token. - Validate and rate-limit user input — bots are public endpoints.
Go-live checklist
- Chosen mode: polling (worker) or webhook (web service)
- Polling: always-on, no scale-to-zero, single instance
- Webhook: HTTPS domain (automatic SSL),
$PORTbind, secret token BOT_TOKENstored as a secret- Database for stateful conversations
- Cronjobs for scheduled messages
References
- [python-telegram-bot docs](https://docs.python-telegram-bot.org/)
- [Telegram Bot API](https://core.telegram.org/bots/api)
- [Telegram webhooks guide](https://core.telegram.org/bots/webhooks)
- [BotFather](https://core.telegram.org/bots/features#botfather)
Whether you poll (an always-on PandaStack worker) or use webhooks (a web service with automatic SSL), PandaStack covers both shapes, with a managed database for state and cronjobs for schedules. Deploy your Telegram bot on the free tier at [dashboard.pandastack.io](https://dashboard.pandastack.io).