Back to Blog
Tutorial10 min read2026-07-03

How to Deploy a Telegram Bot in Python

Deploy a python-telegram-bot to production: the crucial polling-vs-webhook decision, which hosting shape each one needs, securing the token, and persisting conversation state.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

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:

ModeHow updates arriveHosting shapePublic port
Long pollingBot repeatedly asks Telegram for updateslong-running workerno
WebhookTelegram POSTs updates to your HTTPS URLweb serviceyes (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_TOKEN as 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), $PORT bind, secret token
  • BOT_TOKEN stored 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).

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also