Scala JavaScript CSS HTML
Fetching latest commit…
Cannot retrieve the latest commit at this time.

Idiomatic Scala wrapper for the Telegram Bot API


The full API is supported: Payments, inline queries, upload files, callbacks, custom markups, games, stickers, chat actions... while being strongly-typed, fully asynchronous, and transparently camelCased.

Table of contents


Add to your build.sbt file:

libraryDependencies += "info.mukel" %% "telegrambot4s" % "3.0.15"

Leaking bot tokens

Don't ever expose your bot's token.

Here's how to avoid unintentional token sharing:

object SafeBot extends TelegramBot with Polling with Commands {
  // Use 'def' or 'lazy val' for the token, using a plain 'val' may/will
  // lead to initialization order issues.
  // Fetch the token from an environment variable or untracked file.
  lazy val token = scala.util.Properties

  onCommand('hello) { implicit msg => reply("My token is SAFE!") }

Webhooks vs Polling

Both methods are fully supported. Polling is the easiest method; it can be used locally without any additional requirements. It has been radically improved, doesn't flood the server (like other libraries do) and it's pretty fast.

Using webhooks requires a server (it won't work on your laptop). For a comprehensive reference check Marvin's Patent Pending Guide to All Things Webhook.


Payments are supported since version 3.0; refer to official payments documentation for details. I'll support developers willing to integrate and/or improve the payments API; please report issues here.


Games support comes in two different flavors, self-hosted (served by the bot itself), and external, hosted on e.g. GitHub Pages. Check both the self-hosted and GitHub-hosted versions of the popular 2048 game.


Beside the usual ways, I've managed to use run bots on a Raspberry Pi 2, and most notably on an old Android (4.1.2) phone with a broken screen.

Distribution/deployment is outside the scope of the library, but all platforms where Java is supported should be compatible (with the notable exception of Google AppEngine). You may find sbt-assembly and sbt-docker very useful.


Just import info.mukel.telegrambot4s._, api._, methods._, models._, declarative._ and you are good to go.

A note on implicits

A few implicits are provided to reduce boilerplate, but are discouraged because unexpected side-effects.

Think seamless/scary T => Option[T] conversion, Markdown string extensions (these are fine)...
Be aware that, for conciseness, most examples need the implicits to compile, be sure to include them.

import info.mukel.telegrambot4s.Implicits._

Running the examples

Clone this repo and get into the test console in sbt

[info] Loading global plugins from ~/.sbt/0.13/plugins
[info] Loading project definition from ~/telegrambot4s/project
[info] Set current project to telegrambot4s (in build file:~/telegrambot4s/)
[rootProject]> project examples
[info] Set current project to examples (in build file:~/telegrambot4s/)
[examples]> console
[info] Starting scala interpreter...
Welcome to Scala 2.12.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_141).
Type in expressions for evaluation. Or try :help.

scala> new RandomBot("TOKEN").run()

Change RandomBot to whatever bot you find interesting here.


Let me Google that for you! (full example)

object LmgtfyBot extends TelegramBot with Polling with Commands {
  def token = "TOKEN"

  onCommand("/lmgtfy") { implicit msg =>
    withArgs { args =>
        "" + URLEncoder.encode(args.mkString(" "), "UTF-8"),
        disableWebPagePreview = true

Google TTS (full example)

object TextToSpeechBot extends TelegramBot with Polling with Commands with ChatActions {
  def token = "TOKEN"
  val ttsApiBase = ""
  onCommand('speak, 'talk, 'tts) { implicit msg =>
    withArgs { args =>
      val text = args mkString " "
      val url = ttsApiBase + URLEncoder.encode(text, "UTF-8")
      for {
        response <- Http().singleRequest(HttpRequest(uri = Uri(url)))
        if response.status.isSuccess()
        bytes <-  Unmarshal(response).to[ByteString]
      } /* do */ {
        uploadingAudio // Hint the user
        val voiceMp3 = InputFile("voice.mp3", bytes)
        request(SendVoice(msg.source, voiceMp3))

Using webhooks

object RandomBot extends TelegramBot with Webhook with Commands {
  def token = "TOKEN"
  override val port = 8443
  override val webhookUrl = ""

  val rng = new Random(System.currentTimeMillis())
  onCommand("coin", "flip") { implicit msg => reply(if (rng.nextBoolean()) "Head!" else "Tail!") }
  onCommand("real") { implicit msg => reply(rng.nextDouble().toString) }
  onCommand("die") { implicit msg => reply((rng.nextInt(6) + 1).toString) }
  onCommand("dice") { implicit msg => reply((rng.nextInt(6) + 1) + " " + (rng.nextInt(6) + 1)) }
  onCommand("random", "rand") { implicit msg =>
    withArgs {
      case Seq(Extractors.Int(n)) if n > 0 =>
      case _ =>
        reply("Invalid argumentヽ(ಠ_ಠ)ノ")
  onCommand("/choose", "/pick") { implicit msg =>
    withArgs { args =>  
      reply(if (args.isEmpty) "Empty list." else args(rng.nextInt(args.size)))

Custom extensions

It's rather easy to augment your bot with custom DSL-ish shortcuts; e.g. this authenticatedOrElse snippet is taken from the AuthenticationBot example.

  onCommand("/secret") { implicit msg =>
    authenticatedOrElse {
      admin =>
             |The answer to life the universe and everything: 42.
             |You can /logout now.""".stripMargin)
    } /* or else */ {
      user =>
        reply(s"${user.firstName}, you must /login first.")

Check out the sample bots for more functionality.


This library uses Semantic Versioning. For the versions available, see the tags on this repository.


  • Alfonso² Peterssen - Owner/maintainer - :octocat: mukel

Looking for maintainers!

See also the list of awesome contributors who participated in this project. Contributions are very welcome, documentation improvements/corrections, bug reports, even feature requests.


This project is licensed under the Apache 2.0 License - see the LICENSE file for details.