Creating a Discord to Telegram Bot: Instant Voice Channel Alerts

Freddy Amarante
9 min readSep 7, 2023

--

A wallpaper for inspired by Discord’s art!

If you’re a fellow gamer, you’re likely familiar with the joy of connecting with friends on Discord to indulge in some online gaming fun. But, here’s the kicker — adulting hit us hard, and it became nearly impossible to get everyone into the voice channel for a chat. To address this issue with my group of gaming buddies, I set up a Telegram group to coordinate when our next gaming session will be. Initially, I relied on manual tagging to gather everyone, but soon, as a programmer I felt the the need for automation. Plus, it turned out to be a cool little side project to dive into the secrets of Discord and Telegram APIs.

The purpose of this article is to teach you how to use two libraries (‘discord.js’ and ‘node-telegram-bot-api’) using Node.js to create a bot that will notify via Telegram when someone enters or leaves a voice channel in a Discord server.

Creating a Discord Application and a Bot

Creating our Bot

  1. First, enter https://discord.com/developers/applications, there you will create an application, give it the name you want and confirm it by clicking the “Create” button.
  2. Head to the “Bot” tab, there you will create a bot, also give it the name you want and a funny profile picture. In this same section, you’ll press the button “Reset Token” and confirm it.
  3. After that, you’ll see that it gave you a string of random characters, this is your bot’s TOKEN. You want to copy the entirety of the string and paste it somewhere safe (and don’t share it with anyone). We’ll need this token soon to be able to tell our bot what to do.

Adding the Bot to a server

  1. Once we have our bot set up, we need to get a bot invite link to be able to add it to our server. Enter to My Apps again, click on the application we created and then go to the “OAuth2” page.
  2. Head to the “OAuth2 URL generator” in the sidebar. There, select the bot and applications.command options.
  3. Copy the link that was generated (it should look similar to this: ‘https://discord.com/api/oauth2/authorize?client_id=1111111111&permissions=0&scope=bot%20applications.commands’) and open it in your browser.
  4. There you will be asked which server you want your bot to enter, select the your server and click the button “Authorize”. If you did all of these steps right you should see that your Bot is now a member of the server!

Note: You need to be the the owner of said server to be able to add bots to it, or to have the “Manage Server” permission in it.

Creating a Telegram Bot

  1. Open the Telegram app on your phone or desktop, search for “@BotFather” and click on the result.
  2. You’ll then start a conversation with BotFather, select the “New Bot” option to start creating your new bot. Give it a name and a username when prompted, you can give it a profile picture if you want.
  3. Once your bot is created, BotFather should give you some information about your bot and the TOKEN to access the HTTP API. Again, store the token somewhere safe and don’t give it to anyone.
  4. In this scenario, our goal is to have our created bot send alerts to a designated Telegram group chat. To make this work, we require the CHAT ID, which is a unique identifier for every Telegram chat. Obtaining the ID of our desired Telegram group is a straightforward process. We can achieve this by temporarily adding bots like “Get My ID” or similar bots to our Telegram group and subsequently removing them. These bots promptly send the CHAT ID in a message, simplifying the process for us. All that’s left to do is copy the ID and save it for later, as we’ll need it in the subsequent steps.

If you want your bot to just notify yourself, you can use your own CHAT ID instead.

Note: If you followed all the steps correctly so far, we should now have two bots; one in Discord and the other in Telegram. Currently, these two bots can’t do anything since nothing is telling them what to do, which is why the next step is to use Node.js to build the functionality of the bot. Also, it’s worth to remember that at this point, we should have at hand three things: Both Telegram and Discord’s API tokens, and the CHAT ID where our bot’s messages will be sent to.

Coding the functionality of our Bot using Node.js

Now that we have all the prerequisites to start coding, make sure to have Node.js installed, for this project I have the version 18.0. The first thing we have to do is to create a folder where our code will be stored, and open a terminal or command prompt in that directory. Once we have done that we have to initialize our project:

npm init -y

To start programming we need to install two depedencies: discord.js and node-telegram-bot-api. We can make this project without using these libraries and only making use of Discord and Telegram’s API, but these libraries make the proccess much easier.

These are the install commands:

npm i discord.js
npm i node-telegram-bot-api

Inside our directory we will create a file called app.js, this is where most of our logic is going to be.

Also, create a file called config.json. Inside we will store both Discord and Telegram’s API tokens and our CHAT ID.

{
"discordToken": "YOUR_DISCORD_BOT_TOKEN_HERE",
"telegramToken": "YOUR_TELEGRAM_BOT_TOKEN_HERE",
"chatId": "YOUR_TELEGRAM_GROUP_CHAT_ID_HERE"
}

Now in app.js:

const fs = require('node:fs');
const path = require('node:path');
const { Client, GatewayIntentBits } = require('discord.js');
const TelegramBot = require('node-telegram-bot-api');

We first import the modules and libraries, including fs for file system operations, path for working with file paths, discord.js for Discord bot functionality, and node-telegram-bot-api for Telegram bot functionality.

const { discordToken, telegramToken, chatId } = require('./config.json');

Add the line above to load the configuration variables (bot tokens and CHAT ID) from config.json.

const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates],
});
const telegramBot = new TelegramBot(telegramToken, { polling: true });

This section initializes instances of the Discord and Telegram bots using the provided tokens. The Discord bot is configured with specific intents to receive updates related to guilds and voice states.

Now create a folder inside the project’s directory called events. In this folder we will create individual JavaScript modules called events, these are pieces of code that will trigger once we receive certain type of ‘messages’ from Discord’s API.

In this article I’m only explaining how to set up a single event (Voice State Update) but in case anytime in the future you want to delve into other functionalities for your bot, add this line of code to dynamically load event handlers from files located in the events directory.

Add this to app.js:

const eventsPath = path.join(__dirname, 'events');
const eventFiles = fs.readdirSync(eventsPath).filter((file) => file.endsWith('.js'));
for (const file of eventFiles) {
const filePath = path.join(eventsPath, file);
const event = require(filePath);
if (event.once) {
client.once(event.name, (...args) => event.execute(...args, telegramBot, chatId));
} else {
client.on(event.name, (...args) => event.execute(...args, telegramBot, chatId));
}
}

The event handlers can execute functions when specific events occur, and they receive the telegramBot and chatIdas additional arguments.

And finally, add this line of code to log in your Discord bot using the provided Discord token, allowing it to connect to the Discord server and start listening for events.

client.login(discordToken);

app.js should look like this:

const fs = require('node:fs')
const path = require('node:path')

const { Client, GatewayIntentBits } = require('discord.js')
const TelegramBot = require('node-telegram-bot-api')

const { discordToken, telegramToken, chatId } = require('./config.json')

const client = new Client({
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildVoiceStates],
})

const telegramBot = new TelegramBot(telegramToken, { polling: true })
const eventsPath = path.join(__dirname, 'events')
const eventFiles = fs
.readdirSync(eventsPath)
.filter((file) => file.endsWith('.js'))

for (const file of eventFiles) {
const filePath = path.join(eventsPath, file)
const event = require(filePath)
if (event.once) {
client.once(event.name, (...args) =>
event.execute(...args, telegramBot, chatId)
)
} else {
client.on(event.name, (...args) =>
event.execute(...args, telegramBot, chatId)
)
}
}

client.login(discordToken)

Now what we need to do is to create the event. In our case, we want to listen to the VoiceStateUpdate event.

In the events folder create a file called voiceStateUpdate.js. Once done, copy and paste the code below inside.

const { Events } = require('discord.js')

const userCooldowns = new Map()

const COOLDOWN_DURATION = 10000

module.exports = {
name: Events.VoiceStateUpdate,
execute(oldState, newState, telegramBot, chatId) {
try {
const userId = newState.member.id
const currentTime = Date.now()

if (userCooldowns.has(userId) && currentTime - userCooldowns.get(userId) < COOLDOWN_DURATION) {
return
}

userCooldowns.set(userId, currentTime)

if (!oldState.channel && newState.channel) {
const user = newState.member.displayName
const channelName = newState.channel.name
const guildName = newState.guild.name

const message = `${user} just entered the '${channelName}' voice channel in ${guildName}`
telegramBot.sendMessage(chatId, message)
} else if (oldState.channel && !newState.channel) {
const user = oldState.member.displayName
const channelName = oldState.channel.name
const guildName = oldState.guild.name

const message = `${user} just left the '${channelName}' voice channel in ${guildName}`
telegramBot.sendMessage(chatId, message)
}
} catch (e) {
console.log(e)
}
},
}
  1. This module is designed to handle the VoiceStateUpdate event from Discord.js. It listens for changes in a user's voice state, such as entering or leaving a voice channel.
  2. The userCooldowns Map is used to keep track of users and their last event timestamps. This is to prevent spamming of alerts by imposing a cooldown duration.
  3. COOLDOWN_DURATION is set to 10,000 milliseconds (10 seconds) and represents the time a user needs to wait before triggering another alert after the initial event.
  4. In the execute function, it first retrieves the user's ID and the current timestamp.
  5. It then checks if the user is still within the cooldown period, and if so, it returns early without processing the event.
  6. If the user is not in cooldown, it updates the cooldown timestamp for the user.
  7. The code then checks if the user transitioned from not being in a voice channel (!oldState.channel) to being in a voice channel (newState.channel exists). If this is the case, it constructs a message indicating that the user entered a specific voice channel in a particular guild and sends this message to the specified Telegram chat.
  8. Conversely, if the user transitioned from being in a voice channel (oldState.channel exists) to not being in a voice channel (!newState.channel), it constructs a message indicating that the user left a specific voice channel in a particular guild and sends this message to the specified Telegram chat.

Run the bot!

Open the terminal in the directory and run the command node app.js to run the script. This should log the Discord bot in and start listening for events. You can now enter or leave any voice channel in your Discord server and check if you received a message in your Telegram group by the bot you set up.

If you followed all the steps correctly it should be working just fine! However, if you don’t receive anything try double checking the code and console logging at different parts of it to check that all imports are working fine, all functions are well written and to detect where the problem may be presenting.

Conclusion

Now that you’ve finished you should have a Discord-to-Telegram voice channel status update notifier working perfectly! Now you and all your group of friends will now when someone entered the voice channel without telling the others, so y’all can have a beautiful gaming session and your entire group of friends can’t make deaf ears!

There are a few features you can add to the project to make things a little more fun to you and your friends and to make the project better overall:

  • Create a whitelist: If your Discord server has a lot of members and you don’t want all of them to be able to trigger the voiceStateUpdate.js event, you can create a list of members who will cause telegramBot to send a message to your Telegram group, and if the user who triggered the event isn’t inside that list then nothing will happen.
  • Check for an specific voice channel: Inside the Discord server, create a voice channel and give it a name different than the others. Apply the same logic to the previous recommendation, if the Voice State Update event comes from a voice channel other than the one you specify, then don’t do anything. Do this if you want your bot to only apply in a specific voice channel.
  • Create a random message generator: Having your bot only say who entered/left which voice channel in which Discord server may be kinda dull. Spice things up by creating a random message generator by creating a function which picks a random index from an array of dynamic strings, so that way each time the event triggers it sends a random message with maybe a few inside jokes.

Here are a few resources in case you want to delve more into Discord and Telegram API:

And here’s my GitHub repository for this project:

--

--

Freddy Amarante

A Front-End developer looking to share my knowledge and project!