Using Discord.JS in Web3

Hey friends, I just wanted to write an appreciation post for the awesome and well-documented library Discord.JS. Considering how the documentation for app integration libraries generally is, I really appreciated how well-documented and explained Discord.JS is.

Using Discord.JS in Web3
Photo by Alexander Shatov / Unsplash

Hey friends, I just wanted to write an appreciation post for the awesome and well-documented library Discord.JS. Considering the general state of documentation for libraries, I really appreciated how well-documented and explained Discord.JS is.

To truly appreciate the documentation yourself, you can have a look at the official Type documentation at, or the official guide with examples at Few companies go this extra mile to make the developer's experience better.

Disclaimer: This article assumes a basic familiarity with the web3 ecosystem. If you're unfamiliar with certain terms, feel free to search them online or reach out.

At Noble, where we're building user authorization tools for DAOs. Since most DAOs run their communities from Discord, Discord.JS is a very important part of our stack. Users can sign up via a Noble-generated landing page, eg, ENS Login or Sound Login, verify that they pass certain requirements like holding tokens or an NFT, and gain access to the Discord server.

However, it's possible that users join in via the Discord server, and have to figure out how to verify themselves. Logging in via a link from within Discord gives us essential details like their Discord user ID, and the server that they're a part of.

Since a regular login flow involves a user coming to a DAO's signin page and providing all these details by themselves, the inline login button helps in short-circuiting the authorization process, allowing us to focus on verifying and authorizing users for roles on the server (which might give them access to private channels within the server).

An example of our Discord OTP integration

The 2 main commands on Discord.JS which make this possible are:

  1. Setting Global Commands across servers for a bot
  2. Handling Interactions - reacting to buttons or commands
  3. Responding to interactions

Here's how it works.

Setting Global Commands

Every good Discord bot needs a set of commands which can be accessed via the / menu. Below is an example of what a list of / commands can look like. For eg,

  • A /start command which initiates connection to the backend and returns important information on how to use the bot.
  • A /createloginlink command which generates a read-only login button for use by a server's users.
  • A /help or /support command to get support for your query.

All of this is already very well-documented here.

Handling Interactions

Handling interactions in Discord, for eg, button clicks or commands, is a real breeze in Discord.JS. The developer has to only create a handler, and check the properties of incoming interaction events via helpful methods like isButton() or isCommand().

client.on('interactionCreate', interaction => {

Responding to Interactions

There are 2 ways of responding to a command, Regular and Ephemeral.

Regular replies appear as replies to the original command. These replies are visible to everyone in the channel.

On the other hand, ephemeral replies appear as user-specific replies which can be dismissed at any time. Since these replies are user-specific and not visible to other members of the channel, the developer can push unique data like OTPs or login-links via this method. This is what we use to display unique login buttons for users as well.

In the above interactions, replies can either be displayed as text, buttons, or other formats.

This setup describes how the login button on Noble works. I hope I explained it well, and am able to convince you to create a Discord bot using Discord.JS :)

Thanks for reading the article this far. If you liked my writing, consider subscribing to my newsletter below, or send me a tweet on @thewritingdev.