If you’re interested in building a game or social experience in an iframe, you can follow the tutorial for building an Activity.
What we'll be building
What we'll be building
Here’s what the finished app will look like:To make the user flow a bit more explicit:
- User A initiates a new game and picks their object using the app’s
/challengeslash command - A message is sent to the channel with a button inviting others to accept the challenge
- User B presses the Accept button
- User B is sent an ephemeral message where they select their object of choice
- The result of the game is posted back into the original channel for all to see
Resources used in this guide
Resources used in this guide
- GitHub repository where the code from this guide lives along with some additional feature-specific code examples.
- discord-interactions, a library that provides types and helper functions for Discord apps.
- Express, a popular JavaScript web framework we’ll use to create a server where Discord can send us requests.
- ngrok, a tool that lets us tunnel our local server to a public URL where Discord can send requests.
Step 0: Project setup
Before we get started, you’ll need to set up your local environment and get the project code from the sample app repository.We’ll be developing our app locally with a little help from ngrok, but you can use your preferred development environment.
Project structure
Project structure
Step 1: Creating an app
First, you’ll need to create an app in the developer portal if you don’t have one already. Navigate to https://discord.com/developers/applications?new_application=true and enter a name for your app, then press Create. After you create your app, you’ll land on the General Information page of the app’s settings where you can update basic information about your app like its description and icon. You’ll also see an Application ID and Interactions Endpoint URL, which we’ll use a bit later in the guide.Fetching your credentials
We’ll need to set up and fetch a few sensitive values for your app, like its token and ID. Back in your project folder, rename the.env.sample file to .env. This is where we’ll store all of your app’s credentials.
We’ll need three values from your app’s settings for your .env file:
- On the General Information page, copy the value for Application ID. In
.env, replace<YOUR_APP_ID>with the ID you copied. - Back on the General Information page, copy the value for Public Key, which is used to ensure HTTP requests are coming from Discord. In
.env, replace<YOUR_PUBLIC_KEY>with the value you copied. - On the Bot page under Token, click “Reset Token” to generate a new bot token. In
.env, replace<YOUR_BOT_TOKEN>with your new token.
Configuring your bot
Newly-created apps have a bot user enabled by default. Bot users allow your app to appear and behave similarly to other server members when it’s installed to a server. On the left hand sidebar in your app’s settings, there’s a Bot page (where we fetched the token from). On this page, you can also configure settings like its privileged intents or whether it can be installed by other users.What are intents?
What are intents?
Intents determine which events Discord will send your app when you’re creating a Gateway API connection. For example, if you want your app to perform an action when users add a reaction to a message, you can pass the
GUILD_MESSAGE_REACTIONS (1 << 10) intent.Some intents are privileged, meaning they allow your app to access data that may be considered sensitive (like the contents of messages). Privileged intents can be toggled on the Bot page in your app’s settings, but they must be approved before you verify your app. Standard, non-privileged intents don’t require any additional permissions or configurations.More information about intents and a full list of available intents (along with their associated events) is in the Gateway documentation.Choosing installation contexts
Now we’ll select where your app can be installed in Discord, which is determined by the installation contexts that your app supports.What are installation contexts?
What are installation contexts?
Installation contexts determine where your app can be installed: to servers, to users, or both. Apps can choose which installation contexts they support within the app’s settings.
- Apps installed in a server context (server-installed apps) must be authorized by a server member with the
MANAGE_GUILDpermission, and are visible to all members of the server. - Apps installed in a user context (user-installed apps) are visible only to the authorizing user, and therefore don’t require any server-specific permissions. Apps installed to a user context are visible across all of the user’s servers, DMs, and GDMs — however, they’re limited to using commands.
Some apps may only want to support one installation context — for example, a moderation app may only support a server context. However, by default, we recommend supporting both installation contexts. For detailed information about supporting user-installed apps, you can read the user-installable app tutorial.
Setting up an install link
Install links provide an easy way for users to install your app in Discord. On the Installation page, go to the Install Link section and select “Discord Provided Link” if it’s not already selected. When Discord Provided Link is selected, a new Default Install Settings section will appear, which we’ll configure next.Adding scopes and bot permissions
Apps need approval from installing users to perform actions in Discord (like creating a slash command or fetching a list of server members). Let’s add scopes and permissions before installing the app.What are scopes and permissions?
What are scopes and permissions?
When creating an app, scopes and permissions determine what your app can do and access in Discord.
- OAuth2 Scopes determine what data access and actions your app can take, granted on behalf of an installing or authenticating user.
- Permissions are the granular permissions for your bot user, the same as other users in Discord have. They can be approved by the installing user or later updated within server settings or with permission overwrites.
- For User Install, add the
applications.commandsscope - For Guild Install, add the
applications.commandsscope andbotscope. When you selectbot, a new Permissions menu will appear to select the bot user’s permissions. SelectSend Messagesto start.
Installing your app
When developing apps, you should build and test on your user account (for user-installable apps) and in a server that isn’t actively used by others (for server-installable apps). If you don’t have your own server already, you can create one for free.
Step 2: Running your app
With your app configured and installed to your test server and account, let’s take a look at the code.To make development a bit simpler, the app uses discord-interactions, which provides types and helper functions. If you prefer to use other languages or libraries, check out the Community Resources documentation.
Installing slash commands
To install slash commands, the app is using
node-fetch. You can see the implementation for the installation in utils.js within the DiscordRequest() function.register script you can use to install the commands in ALL_COMMANDS, which is defined at the bottom of commands.js. It installs the commands as global commands by calling the HTTP API’s PUT /applications/<APP_ID>/commands endpoint.
If you want to customize your commands or add additional ones, you can reference the command structure in the commands documentation.
In your terminal within the project folder, run the following command:
Step 3: Handling interactivity
To enable your app to receive slash command and other interaction requests, Discord needs a public URL to send them. This URL can be configured in your app’s settings as Interaction Endpoint URL.Set up a public endpoint
To set up a public endpoint, we’ll start our app which runs an Express server, then use ngrok to expose our server publicly. First, go to your project’s folder and run the following to start your app:3000. Behind the scenes, our app is ready to handle interactions from Discord, which includes verifying security request headers and responding to PING requests.
By default, the server will listen to requests sent to port 3000, but if you want to change the port, you can specify a
PORT variable in your .env file.Adding an interaction endpoint URL
Go to your app’s settings and on the General Information page under Interaction Endpoint URL, paste your new ngrok forwarding URL and append/interactions.
Click Save Changes and ensure your endpoint is successfully verified.
If you have trouble verifying your endpoint, make sure both ngrok and your app are running on the same port, and that you’ve copied the ngrok URL correctly.
- It uses the
PUBLIC_KEYand discord-interactions package with a wrapper function (imported fromutils.js) that makes it conform to Express’sverifyinterface. This is run on every incoming request to your app. - It responds to incoming
PINGrequests.
Handling slash command requests
With the endpoint verified, navigate to your project’sapp.js file and find the code block that handles the /test command:
/test slash command works. When you trigger it, your app should send a message that contains “hello world” followed by a random emoji.
In the following section, we’ll add an additional command that uses slash command options, buttons, and select menus to build the rock-paper-scissors game.
Step 4: Adding message components
The/challenge command will be how our rock-paper-scissors-style game is initiated. When the command is triggered, the app will send message components to the channel, which will guide the users to complete the game.
Adding a command with options
The/challenge command, called CHALLENGE_COMMAND in commands.js, has an array of options. In our app, the options are objects representing different things that a user can select while playing rock-paper-scissors, generated using keys of RPSChoices in game.js.
You can read more about command options and their structure in the documentation.
Handling the command interaction
Handling the command interaction
To handle the The above code is doing a few things:
/challenge command, add the following code after the if name === "test" if block:- Parses the request body to get the ID of the user who triggered the slash command (
userId), and the option (object choice) they selected (objectName). If the interaction is run in a server (context === 0), the user ID will be nested in thememberobject. If it’s in a DM or Group DM, it will be in theuserobject. - Adds a new game to the
activeGamesobject using the interaction ID. The active game records theuserIdandobjectName. - Sends a message back to the channel with a button with a
custom_idofaccept_button_<SOME_ID>.
components array. Actionable components (like buttons) need to be inside of an action row, which you can see in the code sample.Note the unique custom_id sent with message components, in this case accept_button_ with the active game’s ID appended to it. A custom_id can be used to handle requests that Discord sends you when someone interacts with the component, which you’ll see in a moment.Handling button interactions
Handling button interactions
Handling select menu interactions
Handling select menu interactions
Next steps
Congrats on building your first Discord app! Hopefully you learned a bit about Discord apps, how to configure them, and how to make them interactive. From here, you can continue building out your app or explore what else is possible.Overview of Apps
Explore the platform features and APIs you have access to when building an app on Discord.
Explore developer tools
Explore 1st party and community-built libraries and tools to speed up and simplify your development.
Developing user-installable apps
Tutorial on building and handling interactions for apps installed to a user.
Discord Developers
Join our community to ask questions about the API, attend events hosted by the Discord platform team, and interact with other devs.