Polling and Webhooks

Copy Markdown View Source

ExGram supports two methods for receiving updates from Telegram: Polling and Webhooks.

Polling Mode

Polling is the easiest way to get your bot running. The bot periodically calls getUpdates on the Telegram Bot API to retrieve new messages.

Best for:

  • Development and testing
  • Simple deployments
  • Bots that don't need instant responses
  • Environments where you can't expose a public URL

Basic Polling Setup

# In your application supervision tree
children = [
  ExGram,
  {MyBot, [method: :polling, token: "YOUR_TOKEN"]}
]

Configuring allowed_updates

By default, Telegram sends all update types. You can filter to only the types you need:

In supervision tree:

{MyBot, [
  method: {:polling, allowed_updates: ["message", "edited_message", "callback_query"]},
  token: "YOUR_TOKEN"
]}

In application config:

config :ex_gram, :polling,
  allowed_updates: ["message", "edited_message", "callback_query"]

Supervision tree options override config file settings, allowing per-bot customization.

Available Update Types

  • "message" - New incoming messages
  • "edited_message" - Edited messages
  • "channel_post" - Channel posts
  • "edited_channel_post" - Edited channel posts
  • "inline_query" - Inline queries
  • "chosen_inline_result" - Inline query results chosen by user
  • "callback_query" - Callback button presses
  • "shipping_query" - Shipping query for payments
  • "pre_checkout_query" - Pre-checkout query for payments
  • "poll" - Poll state updates
  • "poll_answer" - User's poll answer

Webhook Cleanup

By default, polling mode deletes any existing webhook. If you've never used webhooks, you can skip this:

config :ex_gram, :polling,
  allowed_updates: ["message"],
  delete_webhook: false

Webhook Mode

Webhooks provide real-time updates. Telegram sends updates to your server via HTTP POST requests.

Best for:

  • Production deployments
  • Bots requiring instant responses
  • High-traffic bots
  • Efficient resource usage

Prerequisites

  1. A public HTTPS URL (HTTP not supported by Telegram)
  2. Valid SSL certificate (self-signed works)
  3. Plug and plug_cowboy dependencies

Setup

1. Add dependencies:

def deps do
  [
    # ... other deps
    {:plug_cowboy, "~> 2.0"},
    {:plug, "~> 1.0"}
  ]
end

2. Add ExGram.Plug to your router:

defmodule MyApp.Router do
  use Plug.Router

  plug ExGram.Plug
  
  # Your other routes...
end

The webhook endpoint will be at /telegram/<bot_token_hash> or you can configure your custom path in the configuration, see Webhook Configuration section

3. Configure your bot:

children = [
  ExGram,
  {MyBot, [method: :webhook, token: "YOUR_TOKEN"]}
]

Webhook Configuration

In Config File

If you configure your webhook options globally, all your bots using webhook will use the same configuration, but they will be independent.

config :ex_gram, :webhook,
  url: "https://bot.example.com",
  path: "/your/own/path",
  allowed_updates: ["message", "callback_query"],
  certificate: "priv/cert/selfsigned.pem",
  drop_pending_updates: false,
  ip_address: "1.1.1.1",
  max_connections: 50,
  secret_token: "your_secret_here"

In Supervision Tree

You can configure it on the supervision tree instead of the global config, to have different configurations per bot for example.

If you configure it this way, and setup a custom path, you have to also configure the plug to use that path.

# application.ex
webhook_options = [
  url: "https://bot.example.com",
  path: "/custom/path",
  allowed_updates: ["message", "callback_query"],
  secret_token: System.get_env("WEBHOOK_SECRET")
]

children = [
  ExGram,
  {MyBot, [method: {:webhook, webhook_options}, token: "YOUR_TOKEN"]}
]

# router.ex
plug ExGram.Plug, path: "/custom/path"

Webhook Options

OptionTypeDescription
urlStringRequired. Your bot's public HTTPS URL (with scheme and optional port)
pathStringThe path that will be used as a callback. If not provided "/telegram" is used.
allowed_updatesList of stringsUpdate types to receive (same as polling)
certificateStringPath to self-signed certificate file
drop_pending_updatesBooleanDrop updates that arrived while bot was down
ip_addressStringFixed IP address for Telegram to use
max_connectionsIntegerMax simultaneous connections (1-100, default 40)
secret_tokenStringSecret token to verify requests are from Telegram

See Telegram setWebhook docs for detailed explanations.

Using Self-Signed Certificates

For development or internal deployments:

config :ex_gram, :webhook,
  url: "https://bot.example.com:8443",
  certificate: "priv/cert/selfsigned.pem"

Generate a self-signed certificate:

openssl req -newkey rsa:2048 -sha256 -nodes -keyout private.key -x509 -days 365 -out cert.pem

Secret Token Verification

Add a secret token for additional security:

config :ex_gram, :webhook,
  url: "https://bot.example.com",
  secret_token: System.get_env("WEBHOOK_SECRET_TOKEN")

Telegram will send this token in the X-Telegram-Bot-Api-Secret-Token header.

Test Environment

Telegram provides a Test Environment for testing your bot without affecting production.

Enable it in config:

config :ex_gram, test_environment: true

Note: You'll need a separate bot token from the test environment's BotFather.

Choosing Between Polling and Webhooks

FeaturePollingWebhooks
Setup complexitySimpleModerate (requires HTTPS)
Real-time updatesDelayed (polling interval)Instant
Server requirementsNonePublic HTTPS endpoint
Resource usageConstant (polling loop)On-demand (per update)
Best forDevelopment, simple botsProduction, high-traffic
NetworkWorks behind firewall/NATRequires public IP

Multiple Bots with Different Methods

You can run different bots with different update methods:

children = [
  ExGram,
  {MyBot.DevBot, [method: :polling, token: dev_token]},
  {MyBot.ProdBot, [method: :webhook, token: prod_token]},
  {MyBot.OtherBot, [method: :webhook, token: other_token]}
]

See Multiple Bots for more details.

Next Steps