Polling vs. Webhooks
Telegram delivers updates through exactly one channel at a time —
poll() and serveWebhook() are mutually exclusive. Pick one per bot
process.
Long polling — Bot.poll()
Simplest option. No public URL, no TLS certificate, works behind NAT/localhost. Good default for development and small bots.
await for (final update in bot.poll()) {
if (update.text == '/start') {
await bot.sendMessage(update.chatId!, 'Hi!');
}
}
Internally this repeatedly calls getUpdates, so if you’ve previously
configured a webhook you should call deleteWebhook first — Telegram
won’t deliver updates to getUpdates while a webhook is active.
Webhooks — Bot.serveWebhook()
Production-style: Telegram pushes updates to an HTTPS URL you control, and
serveWebhook runs a local HTTP server to receive them.
Typical flow:
- Start your server:
await bot.serveWebhook(...). - Register the public URL with Telegram:
await bot.setWebhook(...). - When you want to go back to polling, call
await bot.deleteWebhook()first.
Use getWebhookInfo() at any time to check what Telegram currently has
registered (URL, pending update count, last error, etc).
Which should I use?
| Polling | Webhook | |
|---|---|---|
| Public HTTPS URL required | No | Yes |
| Good for local development | Yes | Needs a tunnel (ngrok, etc) |
| Good for production at scale | Workable, but less efficient | Yes — Telegram pushes only when there’s something to deliver |
| Setup complexity | Minimal | Requires setWebhook + a reachable server |
Example
See example/10_webhook_server.dart for a full runnable webhook setup,
and example/01_basic_echo_bot.dart / example/02_commands_and_text.dart
for polling.
Filtering update types
Both getUpdates (used internally by poll()) and setWebhook accept an
allowedUpdates list built from the UpdateType enum, so you only
receive the update kinds your bot actually handles (e.g. just message
and callbackQuery).