Blog

Building a Telegram Bot using Node.js and Hosting it for Free with Permanent Uptime

28 Jan 2021 - By Christian Meyer

The Telegram messenger has recently seen another great increase in users because of the WhatsApp privacy concerns that have again resurfaced with its new changes to the terms of service. At the time of this writing, it’s sitting comfortably at above 500 million users now. But even before that, its popularity has already been steadily growing because of its performance and wealth of features including a comprehensive bot API. Such Telegram bots can serve a variety of purposes that can even make sense in an enterprise context.

As an example, seeing that there’s so many users on the messenger, you might want to consider using it as a scalable sales or support tool. For this purpose a chat bot that is responding to Telegram messages can make a lot of sense. I will show how to get started with implementing a bot using Node.js in this article. I’ll also give some pointers on how this bot can be deployed on Heroku for free with limited resources.

Register Your Bot

First things first: You need to register your bot with the Telegram API. The easiest way to do that is to just add BotFather to your own Telegram contacts. BotFather is itself a bot for creating and managing your bots. Start a chat with BotFather and use the chat command /newbot to create your bot. BotFather will now guide you through bot creation. You will need to provide a name and a username for your bot. Name corresponds to the human-readable display name that is displayed in the contact list and when the bot sends a message. Username is the bot’s unique identifier that may for example be used to call the bot for inline queries or to add it to a group. Try to keep username short and memorable because users may have to manually type it depending on the bot’s capabilities. An important restriction on the username is that it must end in bot or any capitalization variants of that string.

Having provided name and username to BotFather, it will reply with an API token. Your bot needs to use this token for every request sent to the API, so write that down. But don’t worry, you can always ask BotFather for your bot’s API token again or even create a new one with the /token command. You may want to flesh out your bot’s info and description using the various BotFather commands provided.

I’d personally recommend to also create a staging bot right away, so that you can try out changes on your bot using a different API token without touching the production version.

Building the Bot

How does it all work? In order to create a working bot, you basically need to have an application permanently running somewhere with internet connection that is constantly polling the Bot API for new messages and then parsing and reacting to them appropriately. Of course, you could implement all that by yourself, but there are actually quite a lot of frameworks out there that do the heavy lifting for you. There’s a good choice of languages to pick from to suit your needs and preferences like PHP, Node.js, Python and more. You can take a look at a list of the most popular frameworks here. For this simple example we’ll go with Slimbot as it’s a lean Node.js framework that’ll get us started quickly without much distraction.

Initialization

First thing you need to do, of course, is to initialize your node project and install the Slimbot framework.

  npm init
  npm i slimbot

Now create an index.js or whatever you want your main js-file to be called and initialize a new Slimbot. This is where you’ll need the API token you got from BotFather when you registered the bot. It should be provided as an environment variable and is a requirement for your bot to work, so it would be best to immediately fail if no token is provided.

  const { BOT_API_TOKEN } = process.env;
  if (!BOT_API_TOKEN) {
    console.error(
      "No BOT_API_TOKEN found. Stopping the boot process."
    );
    process.exit(1);
  }

  const Slimbot = require("slimbot");
  const bot = new Slimbot(BOT_API_TOKEN);
Responding to Messages

With your bot object prepared, you’re now able to define how it responds to chat messages.

  bot.on('message', message => {
    // the bot needs a chat id to send its message to
    bot.sendMessage(message.chat.id, "Hello World");
  });

Looks like you could run it and start chatting with it now. But wait, there’s one last thing: Remember that you’ll need your bot to be polling the API? After you’re done declaring all your functions and bot configuration, you simply need to tell your bot to start polling.

  bot.on('message', message => {
    // the bot needs a chat id to send its message to
    bot.sendMessage(message.chat.id, "Hello World");
  });

  // start polling the API for messages
  bot.startPolling();

Now you can run the app and start sending messages to it via any Telegram client and it should respond to you with "Hello World". How you proceed from here is pretty much open to your imagination and depends on the purpose of your bot.

Want a chat bot that takes first-level support requests and is able to provide solutions to common problems or redirect to a human? Integrate a natural language processing framework that is able to understand the messages and take the appropriate actions.

Want a more technical bot that is able to take commands with Arguments and even communicate with some other services? You could integrate yargs and implement a command parser.

Hosting the Bot

You can host this bot anywhere you would be able to host any other Node.js application. Whether its your company’s server, a raspberry Pi or a Cloud service, it all depends on how much resources you’ll expect your bot to need. If you have a particularly lightweight bot though, there’s a very good way to host it with 24/7 uptime completely free. All the services I found that offer free hosting have some downtime period or outright kill the process after some time, requiring you to manually start it back up again. One of those services is one that probably most of you know: Heroku.

If you just deploy the bot on Heroku without any special configuration, it will be considered a web app and go to sleep after some idle time. Since the bot is not hosting a web server that’s going to happen quickly. It’s actually very simple to change this behaviour: Just add a file called Procfile to the root of your app. Open it and enter just the line worker: node index, where index should be replaced with the name of the main entry point of your bot. This will define the bot as a web worker to Heroku and it will be kept alive indefinitely. After uploading your code, check to see that it’s properly configured under Resources -> Free Dynos. You should see two entries there looking something like this:

  • web npm start
  • worker node index

Make sure that web is disabled and worker is enabled and if necessary, restart the Dyno for the changes to take effect. The bot should now be running as a worker.

I’ve been able to keep a private bot running like this for a couple of months before Heroku started to email me about my dyno hours running out at the end of each month. This might have been caused by increased traffic to my bot consuming more of those hours. It was enough for me to enter my credit card details for some extra free dyno hours. But if you intend to run your bot commercially, your hours could quickly exceed your free quota. In that case, paying for Heroku’s great service might not just be unavoidable, but also fair and reasonable.

Final Thoughts

The Telegram Bot API pairs quite nicely with a deployment on Heroku and using the appropriate bot frameworks makes adding functionality pretty easy and straightforward. I’ve had my bot die once in a 3 months period, so I’m confident to say that it works smoothly. Nonetheless, I’d advise you to add some logging to your bot, so you can see what’s going on in the Heroku logs and you might even want to add some crash reporting tool like Sentry to it.

And that’s that. We’re done. Now you have a working Telegram bot that you can exchange “Hello World”-Messages with on lonely nights. Congratulations!


Picture credits:
Adobe Stock

Christian Meyer

I am a software engineer with a passion for app development. I love trying new cutting edge technology and frameworks regarding mobile, desktop or web development and sharing my experiences with the world.