Open-source project
atipugin/telegram-bot-ruby avatar
atipugin/telegram-bot-ruby

telegram-bot-ruby: Long-Polling Telegram Bots in Ruby

Ruby wrapper for Telegram's Bot API

1,425 stars224 forksRubyWTFPL

At a glance

What is it?
telegram-bot-ruby wraps Telegram's Bot API with Ruby clients, typed update objects, keyboards, file handling, proxy configuration, and long-polling listeners. It fits applications that control their own bot process, but it does not provide the webhook server that a hosted deployment needs.
Who is it for?
Adopt telegram-bot-ruby for a Ruby process that can own Telegram long polling or call the client from a separately built webhook service. Do not treat it as a complete hosting framework.
Can I use it commercially?
Yes. WTFPL is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 58 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The Telegram API boundary in telegram-bot-ruby

telegram-bot-ruby is aimed at Ruby developers who want to implement Telegram bots without assembling every Bot API request, response object, and update type by hand. Its scope is a client library, not a complete bot deployment. The application supplies a bot token, chooses how to run the process, and decides how to organize commands and callbacks.

The wrapper exposes Telegram Bot API methods through the `bot.api` object. According to the README, those methods can be invoked as they are defined by Telegram, and the same methods accept both `snake_case` and `camelCase`. That direct API surface is useful when a project needs an endpoint or update type introduced by Telegram. It also means developers may still need to consult Telegram's Bot API reference for request fields, response constraints, permissions, and error conditions.

Incoming data is represented by typed Ruby objects. The README describes the message object as implementing Telegram's `Message` specification. Inline-query examples go further and compare an update against classes such as `Telegram::Bot::Types::CallbackQuery`, `Telegram::Bot::Types::Message`, and `Telegram::Bot::Types::InlineQuery`. Callers can branch on those classes before reading fields. This is more explicit than treating every update as an untyped hash, although it also means dispatch code must account for update categories that the application does not handle.

The library targets the common command bot case. The main example listens for `/start` and `/stop`, obtains the chat identifier from the incoming message, and sends a reply through `send_message`. Keyboard examples add reply keyboards, contact requests, location requests, and inline callbacks. The file-upload section states that the bot can upload photos, audio, documents, and stickers, although the README example ends before showing a complete upload call.

Long Polling, Webhooks, and Update Flow

The primary listener uses Telegram's long-polling path. `bot.listen` yields incoming updates to a Ruby block, and the block can dispatch an update and issue an API request before waiting for more input. The README describes the listener as continuing until `bot.stop` is called, with a delay for the current `fetch_updates` request. This model suits a Ruby process that stays connected to Telegram and does not need an incoming HTTP endpoint.

For a simple command, the data flow is direct. Telegram sends an update to the client, `bot.listen` yields a message object, and application code reads `message.text`. The relevant command then calls `bot.api.send_message` with `message.chat.id` as `chat_id`. Response text can incorporate `message.from.first_name`. There is no command router shown in the basic example, so registration, authorization, persistence, and duplicate handling remain application responsibilities unless another part of the project supplies them.

Webhook deployments follow a different boundary. The README does not describe a Rails, Rack, or other webhook application inside this library. Instead, it tells users to implement their own webhook callback server and points to `solyaris/BOTServer` as an example. That makes the library usable behind a separately operated HTTP service, but it also means infrastructure termination, route authentication, HTTPS, and request parsing are not documented here.

The listener should not be confused with background job processing. The README says nothing about queues, retry policies, update persistence, horizontal replicas, or delivery deduplication. Telegram update handling can therefore fail in familiar ways: an exception in one callback may interrupt processing, and two application instances polling for the same bot token can create operational conflicts. Those concerns are not resolved by the examples and should not be inferred from the wrapper's API coverage.

Installing the Gem and Starting a Command Bot

The README gives both Bundler and direct RubyGems installation paths. For an application-managed bundle, add the documented dependency to the `Gemfile`. The version constraint is copied directly from the project documentation.

ruby
gem 'telegram-bot-ruby', '~> 2.8'

After editing the bundle, run the documented command from the application directory.

bash
bundle

The README also documents a system-wide installation as an alternative.

bash
gem install telegram-bot-ruby

A real first bot needs a token obtained through Telegram's BotFather documentation. Replace the placeholder in a Ruby entry point, load the library, and dispatch two text commands through `bot.api.send_message`.

ruby
require 'telegram/bot'

token = 'YOUR_TELEGRAM_BOT_API_TOKEN'

Telegram::Bot::Client.run(token) do |bot|
  bot.listen do |message|
    case message.text
    when '/start'
      bot.api.send_message(chat_id: message.chat.id, text: "Hello, #{message.from.first_name}")
    when '/stop'
      bot.api.send_message(chat_id: message.chat.id, text: "Bye, #{message.from.first_name}")
    end
  end
end

The token in this example is a placeholder. A deployed bot should obtain the actual secret through the deployment environment rather than committing it. The repository contains an `.env.sample` with `BOT_API_ENV=test` and `BOT_API_TOKEN=`, but the README does not show how that file is loaded, so it would be misleading to prescribe an unstated environment-loading command or gem.

Typed Updates, Keyboards, and Callback Handling

The wrapper separates incoming update classes from the HTTP client. That is important for bots whose updates include more than ordinary text messages. In the inline-keyboard example, a callback query is handled separately from a `Message`, while an `InlineQuery` is handled by producing result objects and passing them to `answer_inline_query`.

A reply keyboard can request contact or location through `KeyboardButton` options. The API models are assembled locally and attached to `send_message` as `reply_markup`. An inline keyboard uses `InlineKeyboardButton` values for URLs, callback data, or inline-query switching. These are direct mappings of Telegram's documented payload structures, so the Ruby class names and Telegram field names are part of the integration surface rather than an independent abstraction.

The examples also show a practical failure mode. The main listener examines `message.text`, but inline mode can yield several update classes. The inline-bots example warns that a variable named `message` can be an instance of any supported update type, so application code should inspect its class before assuming `text`, `from`, or `chat` exists. A callback query and an inline query have different response methods. Ignoring unmatched update types is valid only if the bot deliberately discards them.

Keyboard and inline-query support does not remove Telegram-side constraints. The README links to Telegram's API documentation but does not restate chat permissions, callback-data limits, keyboard visibility rules, or user-consent requirements. Those rules must be checked against the relevant Bot API endpoints rather than inferred from the Ruby constructors.

Proxy Configuration and Network Constraints

The library can point at a configured API URL. The README presents this for environments that reach Telegram through a proxy. The `url` option changes the address used by the client, but it does not describe DNS behavior, certificate handling, health checks, or failover.

ruby
Telegram::Bot::Client.run(token, url: 'https://proxy.example.com') do |bot|
  # ...
end

The placeholder host above is from the documented proxy pattern, not a real endpoint. The reader must provide a proxy that exists and is configured to forward Telegram requests.

A separate path configures the Excon adapter and SOCKS5 proxy address through `Telegram::Bot.configure`. The documented values are `config.adapter =:excon` and `config.adapter_options = { socks5_proxy: 'socks5://socks.proxy:1080' }`. The README links to Excon but does not show that dependency's installation or runtime version requirements, so the example should not be expanded with an invented `Gemfile` entry.

ruby
Telegram::Bot.configure do |config|
  config.adapter = :excon
  config.adapter_options = { socks5_proxy: 'socks5://socks.proxy:1080' }
end

Proxy support is therefore explicit but narrow. It documents two routes, an alternate API URL and an Excon SOCKS5 configuration. It does not establish that either route will work with a given network, Telegram endpoint, or operating system.

Graceful Shutdown, License, and Maintenance

A long-running bot needs a shutdown path, and the README gives one for an `INT` signal. The application creates `Telegram::Bot::Client` directly, traps Ctrl-C, and calls `bot.stop`. The listener remains active until that method is reached, with a small delay associated with the current `fetch_updates` request.

ruby
bot = Telegram::Bot::Client.new(token)

Signal.trap('INT') do
  bot.stop
end

bot.listen do |message|
  # it will be in an infinity loop until `bot.stop` command
end

This is a simple signal integration rather than a full process supervisor. The documentation does not address `TERM`, service-manager timeouts, in-flight API requests, or shutdown behavior under exceptions. A deployment that needs those guarantees must implement them around the client.

The repository is licensed under `WTFPL`. That identifier indicates the project's stated licensing choice, but this review does not interpret its legal effect or substitute for a license review. The repository is not archived, and its last push was on 2026-08-25. The repository also has no GitHub releases, so there is no release cadence or published release note available here to support a version-upgrade schedule.

For upgrades, the Gemfile example pins the `~> 2.8` constraint, while the system-wide command installs the package without that application constraint. Whether a newer 2.x version contains API or behavior changes cannot be established from the repository information. The `CHANGELOG.md` is listed as a repository file, but its contents are not shown, so no specific upgrade changes can be claimed.

Choosing Between Polling and a Webhook Server

telegram-bot-ruby is a sensible fit for a small Ruby command bot that runs as a persistent process, listens through `bot.listen`, and keeps its routing logic in ordinary Ruby blocks. It is also a reasonable client layer for a webhook application, but only if the application supplies the HTTP callback server itself.

It is the wrong choice as the sole deployment component when the project expects the library to terminate HTTPS requests, expose a ready-made route, schedule polling, or manage multiple worker processes. Those capabilities are outside the documented package boundary. A team that needs Rails integration should either implement the callback route around the Telegram types or choose a bot framework whose documentation defines that server layer.

Compared with an independent HTTP integration, the wrapper reduces repetitive Bot API method handling and gives callbacks typed objects such as `Message`, `CallbackQuery`, and `InlineQuery`. Compared with a full bot framework, it stays at the client level: the README provides command examples, not a router, session store, job system, webhook controller, or deployment template. The trade-off is direct control against more application work.

Before adoption, verify the exact gem version selected by Bundler, the Bot API fields used by the bot, the update classes the application will receive, and the delivery mechanism. For a polling bot, also verify that `bot.stop` is connected to the actual service shutdown signal. For a webhook deployment, first identify the separate server implementation, because the library documentation explicitly leaves that part to the developer.

Editorial conclusion

Adopt telegram-bot-ruby for a Ruby process that can own Telegram long polling or call the client from a separately built webhook service. Do not treat it as a complete hosting framework. Verify the selected gem version, supported Bot API methods, expected update types, proxy requirements, and shutdown behavior before deployment.

Frequently asked questions

How do I install telegram-bot-ruby in a Ruby application?

Add `gem 'telegram-bot-ruby', '~> 2.8'` to the `Gemfile` and run `bundle`. The README also documents `gem install telegram-bot-ruby` for a system-wide installation.

Does telegram-bot-ruby include a webhook server?

No. The README says developers must implement their own webhook callback server and links to a separate example repository.

How do I stop a telegram-bot-ruby long-polling bot?

Create the client with `Telegram::Bot::Client.new(token)`, trap the `INT` signal, and call `bot.stop` from the signal handler. The README says the listener stops after the current `fetch_updates` request finishes.

Official sources

  1. atipugin/telegram-bot-ruby on GitHub
  2. Issues
  3. License: WTFPL
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/atipugin-telegram-bot-ruby.svg)](https://hysenlabs.com/projects/atipugin-telegram-bot-ruby)

Was this useful?