# Building Your First Activity in Discord Source: https://docs.discord.com/developers/activities/building-an-activity Step-by-step tutorial for creating your first Discord Activity. [Activities](/developers/activities/overview) are web-based games and apps that can be run within Discord. Activities are embedded in iframes within the Discord client, and can be launched from the App Launcher or when responding to interactions. If this is your first time learning about Activities, check out the [Activities Overview](/developers/activities/overview) for more information and a collection of more advanced [sample projects](/developers/activities/overview#sample-projects). ## Introduction In this guide, we'll be building a Discord app with a basic Activity that handles user authentication and fetches data using the API. It assumes an understanding of [JavaScript](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics) and [async functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function), and a basic understanding of frontend frameworks like [React](https://react.dev/) and [Vue](https://vuejs.org/). If you are still learning to program, there are many free education resources to explore like [The Odin Project](https://www.theodinproject.com/paths/foundations/courses/foundations), [Codecademy](https://www.codecademy.com/learn/paths/web-development), and [Khan Academy](https://www.khanacademy.org/computing/computer-programming/programming). Building Your First Activity Tutorial * **[discord/getting-started-activity](https://github.com/discord/getting-started-activity)**, a project template to get you started * **[@discord/embedded-app-sdk](https://github.com/discord/embedded-app-sdk)**, the SDK used to communicate between your app and Discord when building Activities * **[Node.js](https://nodejs.org)**, latest version * **[Express](https://expressjs.com)**, a popular JavaScript web framework we'll use to create a server to handle authentication and serve our app * **[Vite](https://vite.dev/)**, a build tool for modern JavaScript projects that will make your application easier to serve * **[cloudflared](https://github.com/cloudflare/cloudflared?tab=readme-ov-file#installing-cloudflared)**, for bridging your local development server to the internet *** ## Step 0: Enable Developer Mode Before getting started, you need to enable Developer Mode for your Discord account if you don't already have it enabled. Developer Mode will allow you to run in-development Activities and expose resource IDs (like users, channels, and servers) in the client which can simplify testing. To enable Developer Mode: 1. Go to your **User Settings** in your Discord client. On Desktop, you can access **User Settings** by clicking on the cogwheel icon near the bottom-left, next to your username. 2. Click on **Advanced** tab from the left-hand sidebar and toggle on `Developer Mode`. ## Step 1: Setting up the project Before creating an app, let's set up our project code from the [`discord/getting-started-activity`](https://github.com/discord/getting-started-activity) repository. Open a terminal window and clone the project code: ``` git clone git@github.com:discord/getting-started-activity.git ``` The sample project you cloned is broken into two parts: * `client` is the sample Activity's frontend, built with vanilla JavaScript and integrated with [Vite](https://vitejs.dev/) to help with local development. * `server` is a backend using vanilla JavaScript, Node.js, and Express. However, as you're building your own Activity, you can use whichever backend you prefer. ``` ├── client ├────── main.js -> your Activity frontend ├────── index.html ├────── package.json ├────── rocket.png ├────── vite.config.js ├── server ├────── package.json ├────── server.js -> your Activity backend └── .env -> your credentials, IDs and secrets ``` ### Install project dependencies Before creating our Discord app, let's quickly install your project's frontend dependencies. Navigate to your project folder's `client` directory, which is where all the sample Activity's frontend code lives: ``` cd getting-started-activity/client ``` Then install the project's dependencies and start up the frontend for the sample Activity: ``` # install project dependencies npm install # start frontend npm run dev ``` If you visit [http://localhost:5173/](http://localhost:5173/) you should see a vanilla JS frontend template running with [Vite](https://vitejs.dev/). While it's not much at the moment, in the following steps we'll connect it to the backend services, make it runnable in Discord, and power it up by populating it with data we pull from Discord APIs. By the end of Step 1, you should have: * An understanding of what Discord [Activities](/developers/activities/overview) are * Developer Mode enabled on your Discord account * Cloned the [sample project](https://github.com/discord/getting-started-activity) to your development environment * Installed the front-end dependencies (in the `client` folder) *** ## Step 2: Creating an app With our project set up, let's create our app and configure the Activity. Create a new app in the developer portal if you don't have one already: Create App Enter a name for your app, select a development team, then press **Create**. **Development Team Access** Launching a non-distributed Activity is limited to you or members of the developer team, so if you're collaborating with others during development, create a [developer team](https://discord.com/developers/teams) and set it to the owner when you create the app. 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. ### Choose installation contexts Apps in Discord can be installed to different **[installation contexts](/developers/resources/application#installation-context)**: servers, user accounts, or both. The recommended *and* default behavior for apps is supporting both installation contexts, which lets the installer to choose the context during the installation flow. However, you can change the default behavior by changing the supported installation contexts in your app's settings. As mentioned, installation contexts determine where your app can be installed. The installation context affect things like who can manage the installation, where the app's commands can appear, and the data returned in response to interactions. * Apps installed in a **[server context](/developers/resources/application#server-context)** (server-installed apps) must be authorized by a server member with the `MANAGE_GUILD` permission, and are visible to all members of the server. * Apps installed in a **[user context](/developers/resources/application#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. Details about installation contexts is in the [Application documentation](/developers/resources/application#installation-context) and the [Developing a User-Installable App tutorial](/developers/tutorials/developing-a-user-installable-app). Click on [**Installation**](https://discord.com/developers/applications/select/installation) in the left sidebar, then under **Installation Contexts** make sure both "User Install" and "Guild Install" are selected. This will make sure users can launch our app's Activity across Discord servers, DMs, and Group DMs. ### Add a Redirect URI Next, we'll add a Redirect URI, which is where a user is typically redirected to after authorizing with your app when going through the standard OAuth flow. While setting up a Redirect URI is required, the Embedded App SDK automatically handles redirecting users back to your Activity when the RPC [`authorize` command](/developers/developer-tools/embedded-app-sdk#authorize) is called. You can learn more about the OAuth flow and redirect URIs in the [OAuth2 documentation](/developers/topics/oauth2), but since we're only authorizing in an Activity, we'll just use a placeholder value (`https://127.0.0.1`) and let the Embedded App SDK handle the rest. Click on [**OAuth2**](https://discord.com/developers/applications/select/oauth2) in your app's settings. Under **Redirects**, enter `https://127.0.0.1` as a placeholder value then click **Save Changes**. Redirect URI in Activity Settings ### Fetch Your OAuth2 Credentials To use information related to a user (like their username) or a server (like the server's avatar), your app must be granted specific OAuth **scopes**. For our sample app, we'll be requesting three scopes: `identify` to access basic information about a user, `guilds` to access basic information about the servers a user is in, and `applications.commands` to install [commands](/developers/interactions/overview#commands). We'll request these later on in the guide, but a full list of scopes you can request is in the [OAuth2 documentation](/developers/topics/oauth2#shared-resources-oauth2-scopes). When requesting scopes later on, you'll need to pass your app's OAuth2 identifiers. For now, we'll copy these identifiers into your project's environment file. In the root of your project, there is an `example.env` file. From the root of your project, run the following to copy it into a new `.env` file: ``` cp example.env .env ``` **Secure Your Secrets** Your `DISCORD_CLIENT_SECRET` and `DISCORD_BOT_TOKEN` are *highly* sensitive secrets. Never share either secrets or check them into any kind of version control. Back in your app's settings, click on [**OAuth2**](https://discord.com/developers/applications/select/oauth2): 1. **Client ID**: Copy the value for Client ID and add it to your `.env` file as **`VITE_CLIENT_ID`**. This is the public ID that Discord associates with your app, and is almost always the same as your App ID. 2. **Client Secret**: Copy the value for Client Secret and add it to your `.env` as **`DISCORD_CLIENT_SECRET`**. This is a private, sensitive identifier that your app will use to grant an OAuth2 `access_token`, and should never be shared or checked into version control. **Why is there a VITE\_ prefix before our Client ID?** Prefixing the `CLIENT_ID` environment variable with `VITE_` makes it accessible to our client-side code. This security measure ensures that only the variables you intend to be accessible in the browser are available, and all other environment variables remain private. You can read details in the [Vite documentation](https://vitejs.dev/guide/env-and-mode). By the end of Step 2, make sure you have: * Set up a placeholder Redirect URI * Added your app's Client ID and Client Secret to your project's `.env` file. ## Step 3: Setting Up the Embedded App SDK With our project and app set up, we're going to install and configure the [Embedded App SDK](/developers/developer-tools/embedded-app-sdk) which we'll use extensively through the rest of this guide. The Embedded App SDK is a first-party SDK that handles the communication between Discord and your Activity with [commands](/developers/developer-tools/embedded-app-sdk#sdk-commands) to interact with the Discord client (like fetching information about the channel) and [events](/developers/developer-tools/embedded-app-sdk#sdk-events) to listen for user actions and changes in state (like when a user starts or stops speaking). The events and commands available in the Embedded App SDK are a subset of the [RPC API](/developers/topics/rpc) ones, so referencing the RPC documentation can be helpful to understand what's happening under the hood when developing Activities. ### Install the SDK Back in our project's `client` directory from before (`getting-started-activity/client`), install the Embedded App SDK [via NPM](https://www.npmjs.com/package/@discord/embedded-app-sdk): ``` npm install @discord/embedded-app-sdk ``` This will add `@discord/embedded-app-sdk` to `getting-started-activity/client/package.json` and install the SDK in your `node_modules` folder. ### Import the SDK in your Project Once installed, we need to import it into our client code and instantiate it to start the handshake between our app and the Discord client. To instantiate the SDK, we will use the environment variables we set up in Step 2. We also set up a check for the [`ready` event](/developers/developer-tools/embedded-app-sdk#ready) with an async/await function which allows us to output a log or perform other actions once the handshake was successful. In `getting-started-activity/client/main.js`, let's import and instantiate the SDK: ```js theme={"system"} // Import the SDK import { DiscordSDK } from "@discord/embedded-app-sdk"; import "./style.css"; import rocketLogo from '/rocket.png'; // Instantiate the SDK const discordSdk = new DiscordSDK(import.meta.env.VITE_DISCORD_CLIENT_ID); setupDiscordSdk().then(() => { console.log("Discord SDK is ready"); }); async function setupDiscordSdk() { await discordSdk.ready(); } document.querySelector('#app').innerHTML = `

Hello, World!

`; ```
**Time to leave your browser behind** Once you add the SDK to your app, you will *not* be able to view your app inside your web browser. In the next step, we will run your Activity inside of Discord. In the next step, we will go over how to view your app in Discord. By the end of Step 3, make sure you have: * Installed the Embedded App SDK to your project * Imported the SDK in your project's `client/main.js` file *** ## Step 4: Running your app in Discord Let's ensure everything is wired up correctly, enable activities via the dev portal, and then run the Activity in Discord. ### Run your app First, we'll restart the sample app. Open a terminal window and navigate to your project directory's `client` folder, then start the client-side app: ``` cd client npm run dev ``` Your app should start and you should see output similar to the following: ``` VITE v5.0.12 ready in 100 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help ``` We'll use the Local URL as our publicly-accessible URL in the next step. ### Set up a public endpoint Next, we'll need to set up the public endpoint that serves the Activity's frontend. To do that, we'll create a tunnel with a reverse proxy. While we'll be using [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) in this guide, you can use [ngrok](https://ngrok.com/docs) or another reverse proxy solution if you prefer. While your app is still running, open another terminal window and start a network tunnel that listens to the port from the last step (in this case, port `5173`): ``` cloudflared tunnel --url http://localhost:5173 ``` When you run `cloudflared`, the tunnel will generate a public URL and you'll see output similar to the following: ``` Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): https://funky-jogging-bunny.trycloudflare.com ``` Copy the URL from the output, as we'll need to add it to our app's settings. ### Set up your Activity URL Mapping Because Activities are in a sandbox environment and go through the Discord proxy, you'll need to add a public URL mapping to serve your application and make external requests in your Activity. Since we're developing locally, we'll use the public endpoint we just set up. Back in your app's settings, click on the [**URL Mappings** page](https://discord.com/developers/applications/select/embedded/url-mappings) under **Activities** on the left-hand sidebar. Enter the URL you generated from `cloudflared` in the previous step. Configuring your URL Mapping | PREFIX | TARGET | | ------ | --------------------------------------- | | `/` | `funky-jogging-bunny.trycloudflare.com` | Read details about URL Mapping [in the development guide](/developers/activities/development-guides/local-development#url-mapping). ### Enable Activities Next, we'll need to enable Activities for your app. On the left hand sidebar under **Activities**, click [**Settings**](https://discord.com/developers/applications/select/embedded/settings). Find the first checkbox, labeled `Enable Activities`. Turn it on 🎉 Enabling Activities in Settings #### Default Entry Point Command When you enable Activities for your app, a [default Entry Point command](/developers/interactions/application-commands#default-entry-point-command) called "Launch" is automatically created. This [Entry Point command](/developers/interactions/application-commands#entry-point-commands) is the primary way for users to launch your Activity in Discord. By default, interactions with this command will result in Discord opening your Activity for the user and posting a message in the channel where it was launched from. However, if you prefer to handle the interactions in your app, you can update the [`handler` field](/developers/interactions/application-commands#entry-point-handlers) or create your own. Additional details are in the Entry Point command [documentation](/developers/interactions/application-commands#entry-point-commands) and [development guide](/developers/activities/development-guides/user-actions#setting-up-an-entry-point-command). ### Running your Activity in Discord Now that we are pointing Discord to our locally running app, we can launch the Activity in Discord! Navigate to your Discord test server and, in any voice and or text channel, open the App Launcher where your in-development Activity should be present. If you don't see your Activity, you should try searching for its name. Clicking on your app will launch your locally running app from inside Discord! Running your activity **Customizing your Activity** If you'd like to set images for your Activity, you can learn how to do that [here](/developers/activities/development-guides/assets-and-metadata#setting-up-activity-metadata). We're looking pretty good so far, but we haven't wired up any Discord functionality yet. Let's do that next. By the end of Step 4, make sure you have: * Set up a public endpoint * Added an Activity URL Mapping in your app's settings * Enabled Activities for your app * Successfully launched your Activity in Discord *** ## Step 5: Authorizing & authenticating users To authenticate your Activity with the users playing it, we must finish implementing our server-side app and get it talking to the client-side app. We will use `express` for this example, but any backend language or framework will work here. This diagram illustrates the common pattern for granting a user an OAuth2 access\_token: Flow diagram for Oauth2 We will be implementing this pattern in this tutorial, but more example implementations can also be found in this sample project: * [Back-end code](https://github.com/discord/embedded-app-sdk-examples/blob/main/discord-activity-starter/packages/server/src/app.ts) * [Front-end code](https://github.com/discord/embedded-app-sdk-examples/blob/main/discord-activity-starter/packages/client/src/main.ts) ``` # move into our server directory cd server # install dependencies npm install ``` We aren't going to edit the server code here, but it consists of a single POST route for `/api/token` that allows us to perform the OAuth2 flow from the server securely. In the `getting-started-activity/server/server.js` file, the following code should already be present: ```javascript theme={"system"} import express from "express"; import dotenv from "dotenv"; import fetch from "node-fetch"; dotenv.config({ path: "../.env" }); const app = express(); const port = 3001; // Allow express to parse JSON bodies app.use(express.json()); app.post("/api/token", async (req, res) => { // Exchange the code for an access_token const response = await fetch(`https://discord.com/api/oauth2/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams({ client_id: process.env.VITE_DISCORD_CLIENT_ID, client_secret: process.env.DISCORD_CLIENT_SECRET, grant_type: "authorization_code", code: req.body.code, }), }); // Retrieve the access_token from the response const { access_token } = await response.json(); // Return the access_token to our client as { access_token: "..."} res.send({access_token}); }); app.listen(port, () => { console.log(`Server listening at http://localhost:${port}`); }); ``` Now, start the project's backend server: ``` npm run dev ``` You should output similar to the following: ``` > server@1.0.0 dev > node server.js Server listening at http://localhost:3001 ``` We can now run our server and client-side apps in separate terminal windows. You can see other ways to set this up in the other [sample projects](/developers/activities/overview#sample-projects). ### Calling external resources from your activity Before we call your backend activity server, we need to be aware of the Discord proxy and understand how to avoid any Content Security Policy (CSP) issues. Learn more about this topic in the guides for [Constructing a Full URL](/developers/activities/development-guides/networking#construct-a-full-url) and [Using External Resources](/developers/activities/development-guides/networking#using-external-resources). ### Calling your backend server from your client We're almost there! Now, we need our client application to communicate with our server so we can start the OAuth process and get an access token. **What is vite.config.js?** To allow our frontend app to call our Express server, Vite requires us to set up a proxy for `/api/*` to our backend server, which is running on port 3001. In their docs, you can learn more about [Vite](https://vitejs.dev/). Copy the following code in your project's `getting-started-activity/client/main.js` file: ```javascript theme={"system"} import { DiscordSDK } from "@discord/embedded-app-sdk"; import rocketLogo from '/rocket.png'; import "./style.css"; // Will eventually store the authenticated user's access_token let auth; const discordSdk = new DiscordSDK(import.meta.env.VITE_DISCORD_CLIENT_ID); setupDiscordSdk().then(() => { console.log("Discord SDK is authenticated"); // We can now make API calls within the scopes we requested in setupDiscordSDK() // Note: the access_token returned is a sensitive secret and should be treated as such }); async function setupDiscordSdk() { await discordSdk.ready(); console.log("Discord SDK is ready"); // Authorize with Discord Client const { code } = await discordSdk.commands.authorize({ client_id: import.meta.env.VITE_DISCORD_CLIENT_ID, response_type: "code", state: "", prompt: "none", scope: [ "identify", "guilds", "applications.commands" ], }); // Retrieve an access_token from your activity's server const response = await fetch("/api/token", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ code, }), }); const { access_token } = await response.json(); // Authenticate with Discord client (using the access_token) auth = await discordSdk.commands.authenticate({ access_token, }); if (auth == null) { throw new Error("Authenticate command failed"); } } document.querySelector('#app').innerHTML = `

Hello, World!

`; ```
Now if we relaunch our app, we'll be prompted to authorize with Discord using the `identify`, `guilds`, and `applications.commands` scopes. Prompt to authorize Activity **Safe storage of tokens** Access tokens and refresh tokens are powerful, and should be treated similarly to passwords or other highly-sensitive data. Store both types of tokens securely and in an encrypted manner. By the end of Step 5, make sure you have: * Updated your `client/main.js` to call the backend to support user authorization and authentication * Been able to successfully complete the authorization flow for your app when opening your Activity *** ## Step 6: Use the SDK to fetch the channel Now that we have authenticated our users, we can start interacting with contextual Discord information that we can use in our application. Let's use the SDK to get details about the channel that our activity is running in. We can do this by writing a new async function that uses the `commands.getChannel` SDK method. In the same `getting-started-activity/client/main.js` file, paste the following function: ```javascript theme={"system"} async function appendVoiceChannelName() { const app = document.querySelector('#app'); let activityChannelName = 'Unknown'; // Requesting the channel in GDMs (when the guild ID is null) requires // the dm_channels.read scope which requires Discord approval. if (discordSdk.channelId != null && discordSdk.guildId != null) { // Over RPC collect info about the channel const channel = await discordSdk.commands.getChannel({channel_id: discordSdk.channelId}); if (channel.name != null) { activityChannelName = channel.name; } } // Update the UI with the name of the current voice channel const textTagString = `Activity Channel: "${activityChannelName}"`; const textTag = document.createElement('p'); textTag.textContent = textTagString; app.appendChild(textTag); } ``` Now, update the callback after `setupDiscordSdk()` to call the function you just added: ```javascript theme={"system"} setupDiscordSdk().then(() => { console.log("Discord SDK is authenticated"); appendVoiceChannelName(); }); ``` If you close and rejoin the Activity, you should now see the name of the current channel. Discord Activities By the end of Step 6, make sure you have: * Updated your `client/main.js` code to fetch the channel name using the SDK * Added a call to the new function in the callback for `setupDiscordSdk()` *** ## Step 7: Use the API to fetch the guild Since we requested the `identify` and `guilds` scopes, you can also use the authorized `access_token` we received earlier to fetch those resources via the API. In the following code block, we will: 1. Call the [`GET /users/@me/guilds`](/developers/resources/user#get-current-user-guilds) endpoint with `auth.access_token` to get a list of the guilds the authorizing user is in 2. Iterate over each guild to find the guild we are in based on the `guildId` defined in discordSdk 3. Create a new HTML image element with the guild avatar and append it to our frontend In this example, we use a pure `fetch` request to make the API call, but you can us one of the JavaScript [community-built libraries](/developers/developer-tools/community-resources) if you prefer. In the same `client/main.js` file, add the following function: ```javascript theme={"system"} async function appendGuildAvatar() { const app = document.querySelector('#app'); // 1. From the HTTP API fetch a list of all of the user's guilds const guilds = await fetch(`https://discord.com/api/v10/users/@me/guilds`, { headers: { // NOTE: we're using the access_token provided by the "authenticate" command Authorization: `Bearer ${auth.access_token}`, 'Content-Type': 'application/json', }, }).then((response) => response.json()); // 2. Find the current guild's info, including it's "icon" const currentGuild = guilds.find((g) => g.id === discordSdk.guildId); // 3. Append to the UI an img tag with the related information if (currentGuild != null) { const guildImg = document.createElement('img'); guildImg.setAttribute( 'src', // More info on image formatting here: https://docs.discord.com/developers/reference#image-formatting `https://cdn.discordapp.com/icons/${currentGuild.id}/${currentGuild.icon}.webp?size=128` ); guildImg.setAttribute('width', '128px'); guildImg.setAttribute('height', '128px'); guildImg.setAttribute('style', 'border-radius: 50%;'); app.appendChild(guildImg); } } ``` Then, call the new function in the callback for `setupDiscordSdk`: ```javascript theme={"system"} setupDiscordSdk().then(() => { console.log("Discord SDK is authenticated"); appendVoiceChannelName(); appendGuildAvatar(); }); ``` If we relaunch our Activity, we will see the current server's avatar render in our Activity. Discord Activities At this point, you should have your Activity up and running. For Step 7, you should have: * Updated your `client/main.js` code to fetch the guild information using the [`GET /users/@me/guilds`](/developers/resources/user#get-current-user-guilds) API endpoint * Added a call to the new function in the callback for `setupDiscordSdk()` *** ## Next Steps Congrats on building your first Activity! 🎉 This is an intentionally simple example to get you started with the communication between your Activity and Discord using the Embedded App SDK and APIs. From here, you can explore the [Activities documentation](/developers/activities/overview) and other resources. }> Follow our Activities Development Guides for suggested development practices and considerations. }> Try out the full range of Embedded App SDK features in the playground app, or explore some of the other examples }> Join our community to ask questions about the API, attend events hosted by the Discord platform team, and interact with other Activities developers # Activity Design Patterns Source: https://docs.discord.com/developers/activities/design-patterns Best practices and design principles for creating engaging Discord Activities. Before building your Activity, here are some guiding principles for you to consider for a successful user experience. ## Guiding Principles ### Interaction over Isolation * Activities are not for screen-sharing, we already have that built-in! * Give users a way to interact with one another. * User actions should impact the experiences of other participants. ### Expression over Monotony * Our users want to create memorable moments. * Create experiences where users craft moments and react in ways they want to share with others. ### Accessibility over Exclusion * Inclusivity is key. * Reduce the bar to entry for your Activity and reward people for engaging deeply with your experience. *** ## Providing a "Solo-Plus" Experience Successful experiences will be built to accommodate small group sessions ("Plus"), but also playable and enjoyable for the case of single-player ("Solo") sessions. ### Solo or single-player * While most people use Discord with small groups of friends. Consider experiences that are compelling alone, but better together! * If you don't support solo play, expect to see a lot of users peeking into the Activity on their own. Consider what you can do to preview the Activity and compel them to come back with their friends. ### Solo-Plus or small groups of users * Small group sessions (3-8 people) show more engagement and retention from users than single-player experiences. * Letting players join with their friends keeps them coming back for more. ### Large groups of users * While you can set a "max participants" suggestion to users, the only real limit is the number of people who can join a Voice call. * Be aware of how your Activity will behave when there are 25 or more people in the call. *** ## User Presence & Privacy When in an Activity with others, make the actions and presence of the others visible to each player. ### Make actions and presence of the others visible to each player * Users enjoy participating in a space that feels active. * If a user has customized their server nickname or avatar, use their server nickname or avatar in game. * Show when a user is speaking in the voice call, or whether they're active or inactive. Speech bubbles in Bobble League ### Respect user privacy * For Activity sessions that match users from various servers, usernames and avatars should be anonymized by default. * Discord personal identifiers should only be populated into the Activity with user confirmation. * Only use these identifiers when the people who can see them already have access via the server or DM. *** ## Deliver a Quality Experience Make your app fast, easy to join, and maximize fun to launch a crowd favorite. ### Surprise and delight users * Surprise and delight is about caring about the small details of how a person experiences your work. * Put the right emotion in when they least expect it to deliver the magic. Bobble League ### Keep load times as low as possible * This allows for easier drop-in drop-out behavior for the large portion of mobile users on Discord. * See the below [Quality & Testing Recommendations](/developers/activities/design-patterns#quality-and-testing) for key areas of minimum quality support and testing recommendations. * See the below [Technical Considerations](/developers/activities/design-patterns#technical-considerations) for recommendations on how to partition loading and work with various development tools to reduce load times. * Consider different screen sizes and orientations across desktop and mobile devices and make sure UI elements scale appropriately. ### Support drop-in, drop-out behavior * Activities are frictionless to join and easy to discover, so you can expect that users will join mid-experience. Give those users something to do, even if it's just letting them spectate until they can join without being disruptive. In the same vein, users can leave without notice or become afk (away from keyboard). Handle these cases gracefully. * Create a case for users who have joined a call but have not yet started playing or engaging. Allow these users to "spectate" other users who are playing. This can also be helpful for Activities that have an ideal number in mind for play. Support drop-in, drop-out behavior in your Activity ### Make your app as available as possible #### Cross-Platform Support * Supporting desktop and mobile devices will expand your user-base to the widest number of users. * Discord device usage is split between mobile and desktop platforms. #### Discord is a Global Audience * Consider supporting a multitude of languages and cultures to make your app more usable for all Discord users. #### Implement Invites * The Embedded App SDK allows for sending invites from within an Activity out to other friended users. * Add invite buttons to a screen or flow with intentionality, not only on the start screen and at the beginning. Examples of intentional Invite prompting include: * Cases where players leave the activity session * Cases where the minimum number of participants has not been reached (e.g. any activity that needs 2+ to start, or is more fun with more people, or when you need an opponent in a game like Chess.) #### Implement Sharing Discord is a social platform where users talk to each other. Sharing and invites lets your app live and engage in those shared spaces, making it visible and accessible to everyone not currently playing. Things like sharing and invites are important ways to reach into those private, shared spaces and attract other players. * The Embedded App SDK allows for sending an image or gif from within an Activity. * Share photos or GIFs that capture moments of fun and memorable, or something to brag about. Don't make things shareable just to feature the activity. * Sharing a high score alone may not be very engaging, but sharing a really good move made in a game, or a collaborative drawing that creates a memory is a conversation starter and may make others want to join in on the fun. Shared Moment from Chess in the Park #### Activities in Text Channels * The Activity user interface, copy and user flows should not rely on people in voice to explain, organize, clarify, or instruct about how the activity works. * All controls, CTAs, and instructions should be clear enough that folks (especially first time users) playing in a text channel are able to quickly start using the app without needing to talk on voice to learn about it. * Lean on dynamic first-time user experience and "How To Play" instructions, toast messages, Call To Action buttons, etc. but be careful to not over-clutter with copy. ### Monetization Considerations Monetization in Activities will be available soon. Keep the following considerations in mind as you design your Activity. * Avoid prohibitive gates in front of participation (e.g. login wall / paywall), especially early in the user journey. * Avoid monetized unlocks that give unfair advantage to other non-paying players or users (i.e. "pay to win"). * Take advantage of Discord as a social platform: look for opportunities to offer users customizable skins, aesthetic themes, new avatars, etc. *** ## Game Design Considerations ### Build games that are easy to learn, hard to master * Players can often feel pressure when joining a multiplayer game (voice/video) in the moment if they’ve never played before. * Games that have a simple quick reference control scheme that are easily approachable help ease players into an experience without dropping them into the deep end. * An easy to understand game loop combined with easy to digest controls tends to work best. If you have to go through a tutorial to understand the game then it will be intimidating to join a game in the moment. ### Discord users who engage with voice are among our most engaged users * Activity engagement and retention increases when users are in a voice call with friends. ### Consider existing game expectations and tropes * If you're developing a game, you're more likely to attract users who are gamers. * Take advantage of existing tropes and expectations for games of the genre you're developing. * Appeal to the player interests that your game (or game genre) provides, and support those interests as a means to get them coming back. ### Activities close when the last participant in the Activity leaves it * The next time the Activity is launched, even if it’s in the same DM or Voice Channel, it will be a different instance and could have different participants. ### If a game is launched, what % of the time do users reach different phases of the game? * This includes launch → start, as there can be a large dropoff between these two (especially if you don’t support solo play or small group sizes). * This also includes various check points in the game, including what % of sessions that start a game reach the end of that game! * If your Activity has different settings you can start a game with, see if some are more popular or more successful — you may want to change your defaults! * For non-games, you may want to analyze a certain action instead (such as queueing a video / song for a co-watching / co-listening Activity). * If drop-off is really high at a certain point, see if you can figure out why or change flows. ### How many games are played in a session? * More games per session isn’t inherently better (you may have an Activity that is meant to be one long game), but is a good baseline to understand. * If you expect to see a lot of repeat plays per session and don’t, it can be worth digging in to understand more. ### How does the group size impact various key metrics? * For example, are larger sessions more or less likely to reach the end of a game? To replay? Etc. * This can help you catch if your Activity has unexpected weak points in different group sizes — maybe the game drags on if there are too many people or isn’t compelling enough if there’s only two. * Not every Activity needs to be built for robust group sizes, but if you have the option to play with X # of players, it’s good practice to make sure that experience is enjoyable for all involved! *** ## Co-Watching / Co-Listening * Co-watching and co-listening should be more than just screen-sharing. Consider creative ways to make each user's experience impacted by other participants. * Consider providing host-controls so that playback isn't overly chaotic. If host controls are provided, make sure everyone can participate in some way, even if it's just recommending content to the host. * If content is not available for everyone in the activity (for example, geo-restricted content), make sure that information is known when the content is queued and when it's playing. The host is generally interested in creating a good experience for their friends. Playback of content should be in sync with others in a local channel or call. * Familiar design patterns can help to get people to participate in your Activity right away. Most Discord users are extremely familiar with media browsing (Spotify, YouTube, Netflix, etc.) and will immediately understand your content if you follow these patterns. * Mobile device volume can be controlled by a device's built-in controls (volume buttons on the side of the device) and work as expected across desktop, mobile, and browsers. *** ## Technical Considerations ### Developing for the iframe * Remember that you need to contend with the Discord Client itself for resources (CPU, RAM and GPU) as that client is still fully running while executing your Activity. * Prioritize time-to-first-interaction. * Minimize the amount of Web Assembly (WASM) as much as possible in your Activity. * Older iOS devices are especially affected by WebKit's optimization compilation pass of WASM that occurs during the first few minutes of usage of an Activity. To varying degrees, this will cause noticeable stutters, device thermal issues, and possibly degraded Discord's AV quality during those early minutes. * All network traffic is routed through the Discord Proxy for various security reasons. * Create multiple versions of your Activity in the Developer Portal for less and more stable development versioning (e.g. Development, Staging, Production). This allows you to show and test the last stable build while also having development and staging environments. ### Developing in Unity Developing for the iframe in Unity is possible, but will likely require extensive min/maxing of all facets of your game to meet performance and quality standards. Other, web-first, game engines are generally more performant out of the box. *** ## Quality and Testing ### Verify User Interface and User Experience * Ensure all buttons and UI elements function correctly without any blocking issues for standard Activity use or gameplay. * Test Discord usernames handling, ensuring they display appropriately based on the chosen format (Discord username or server identity). ### Test for Performance * Evaluate performance to ensure it is satisfactory for the majority of users across phones, tablets, and desktop machines and across multiple operating systems. * Lag or slowness should not significantly impact the Activity or gameplay experience. ### Test for Audio * Check that sound effects and background music work as intended, with volume settings functioning correctly. * Being able to hear when playing on a voice call is important. ### Validate Activity Controls * Confirm that all game controls, including clicks, drag, key controls, swiping, and hovers, work as expected and are suitable for the platform. * Test in-app tutorials and instructions for accuracy and relevance to the current activity functionality and user platform (desktop or mobile). ### Mobile Device UI Considerations * Watch out for potential issues on devices with top notches or cameras in specific corners that may hide or cut off UI elements and buttons, rendering them untappable. * Be mindful of Android curved screen edges that could obscure or make elements and buttons inaccessible. * Take into account iOS/Android swipe gestures that may interfere with UI elements or buttons located at the bottom of the screen. * Ensure that Android devices with a back button do not overlap with elements or buttons at the bottom of the screen, preventing users from tapping them. * Respect the safe area defined by the platform to prevent any buttons or content from being cut off or non-functional. ### Desktop Accessibility Guidelines * Enable users to cycle through Discord buttons and fields on desktop by pressing TAB repeatedly, ensuring that the activity does not capture control. * Implement the functionality for the ESC key to close any open in-activity modals, providing a consistent user experience. * Opt for color-blind friendly colors with high contrast, especially for crucial game elements that need to be distinguishable based on color. * Avoid using similar colors for objects that are essential for gameplay but differ only in color, as this may pose challenges for color-blind users. # Activity Development Guides Index Source: https://docs.discord.com/developers/activities/development-guides Development guides for building Discord Activities with the Embedded App SDK. These guides include suggested development practices, SDK commands, and user flows for you to consider while building your Activity. These will help to provide your users with a consistent and clear experience while interacting with your application. ## Local Development Get up and running with a local development application. How to launch your app on mobile and desktop Discord clients. Configure the Discord proxy to allow network requests to necessary external endpoints. How to use the various levels of logging while building your application. ## User Actions Open an external link from within your app. Open the Application Channel Invite dialog within Discord. Open a dialog to share media from your application to a channel, DM, or GDM. Configure a command that allows users to open your Activity from the App Launcher. Open a dialog to enable hardware acceleration for compute-intensive applications. ## Mobile Update your application settings to support iOS and Android. Ensure that your app's assets fall within mobile-safe areas. Respond to thermal state changes surfaced from iOS and Android. ## Layout Configure and subscribe to changes in application orientation. Subscribe to layout mode changes to update your application's user interface. ## Networking Working with our Activity Proxy Generate a full URL when working with network requests. Allow network requests to external resources from inside the Discord proxy. Keep things safe and secure in your Activity. ## Multiplayer Experience Managing instances to ensure users join the same instance as their friends. Use the SDK to fetch the users currently connected to an instance. Retrieve and render the usernames and avatars of users connected to your application. Validating activity sessions are via a Discord client before adding them to an instance's session. ## Growth and Referrals Encourage your users to share links to your activity by adding tracking and offering rewards for engagement. For off-platform sharing of rewards, promotions, or limited time experiences. An API to be able to generate ephemeral links with a customizable embed. ## Assets & Metadata Best practices for configuring how your application shows up in Discord. Best practices for configuring how your application shows up in Discord. ## Rich Presence Display live activity data on user profiles while they play your Activity. Design tips and a launch checklist for a polished Rich Presence integration. ## Production Readiness Manage asset caching in your application and the Discord Activity proxy. Stay within rate limits to keep the fun going in your Activity. Network routing considerations when preparing your Activity for production use. Future-proof your application and support new commands as they become available in the SDK. # Assets and Metadata Source: https://docs.discord.com/developers/activities/development-guides/assets-and-metadata Guide to managing Activity assets, metadata, and configuration. ## Setting Up Activity Metadata The Activity Shelf is where users can see what Activities can be played. It has various metadata and art assets that can be configured. To update your app's metadata in the Discord Developer Portal, navigate to the `Settings -> General Information` tab of your app. * **Application Name:** The publicly visible name of your app. * **Application Icon:** The publicly visible icon for your app. * **Application Description:** The application description is shown in the view of the Activity Shelf Item. * **Max Participants:** The max participants indicate the maximum number of players for your application. * Max Participants is displayed above the name in the 1-up view: `Up to X participants`. * Leaving this field empty defaults to `Unlimited participants`. * Max Participants is also displayed under the name in the 2-up view. An app can have a different application name and avatar from the application's bot username and avatar. Both sets of metadata are public-facing and may be visible in various situations when a user interacts with your app. You can view your bot's username on the `Settings -> Bot` tab. *** ## Setting Up Activity Art Assets The Activity Shelf is where users can see what Activities can be played. It has various metadata and art assets that can be configured. To update your app's embedded-specific art assets in the Discord Developer Portal, navigate to the [Activities -> Art Assets](https://discord.com/developers/applications/select/embedded/assets) tab of your app. ## Embedded Background Used as a background overlay in Grid view. Artwork should be clustered around the edges of the image leaving space in the center of the image so the UI does not clash with it. #### Specifications * 16:9 aspect ratio * At least 1024 pixels wide ## Cover Art Used as the main image in the Activity Shelf. It is suggested that this image contain the title and some art in the background. #### Specifications: * Image can be displayed at both 16:9 and 13:11 aspect ratios * At least 1024 pixels wide ## App Tile There are two views of an application tile. The regular size tile (2-up tile) and the larger "featured" application tile (1-up tile). ## Video Preview Hovering over the cover image should start playing a preview video of the Application. The preview videos should be no more than 10 seconds long. If no video is provided, nothing will happen as you hover over the application. #### Specifications: 640 x 360, mp4 format, under 10 seconds long, under 1 MB in size # Growth and Referrals Source: https://docs.discord.com/developers/activities/development-guides/growth-and-referrals Implement growth strategies and referral systems in Discord Activities. ## Prompting Users to Share Incentivized Links Incentivized sharing can help grow your Activity through network effects. You can use links in several different ways such as: * **Referral links.** Users can copy referral links inside your Activity, which include their Discord user ID (`https://discord.com/activities/?referrer_id=123456789`), and they can send to their friends. If their friend accepts and starts playing your game, then you gift the referrer something inside your game. * **Promotions.** You can run a temporary promotion on social media, where you offer a reward if they start playing now. Share a custom link on your social media (`https://discord.com/activities/?custom_id=social012025` ). Anyone who clicks that specific link receives something inside your game. * **Social deep-links.** Currently, when users launch an Activity, they all land in the same place. Instead, you can start deep-linking to contextually relevant points in your game. For example, user A can copy a link inside your Activity for engaging other users (`https://discord.com/activities/?referrer_id=123456789&custom_id=visit-location`), and sends the link to their friends in a DM or channel. Then, user B who clicks the link gets taken directly to user A’s location. * **Turn-based deep-links.** When you send an “it’s your turn” DM to a user, you can include a link which takes them directly to the right game instance and the turn they need to take. * **Affiliate marketing.** You can work with affiliates (influencers, companies, etc) to advertise your game to their followings, and reward them via a custom link (`https://discord.com/activities/?custom_id=influencer1`). Then, for every user that starts playing because of said influencer, you can then pay out to the influencer. * **Source attribution.** You can use the `custom_id` parameter to figure out how much traffic you’re getting from different marketing sources. This guide covers implementing a referral link which will feature a reward system for users who share links and those who click them. #### Implementation Overview 1. Create and track an incentivized link for a promotional campaign, then prompt users to share the link 2. Handle incoming referrals and grant valid rewards #### Sharing Links When implementing sharing, you'll need to: 1. Generate a unique ID for tracking the promotion 2. Call the [`shareLink`](/developers/developer-tools/embedded-app-sdk#sharelink) command 3. Track the share attempt ```javascript theme={"system"} // Generate a unique ID for this promotion // This could be per-campaign, per-user, or per-share depending on your needs const customId = await createPromotionalCustomId(); try { const { success } = await discordSdk.commands.shareLink({ message: 'Click this link to redeem 5 free coins!', custom_id: customId, }); if (success) { // Track successful share for analytics/limiting await trackSuccessfulShare(customId); } } catch (error) { // Handle share failures appropriately console.error('Failed to share link:', error); } ``` #### Handling Incoming Referrals When a user clicks a shared link, your activity will launch with referral data available through the SDK: ```javascript theme={"system"} // Early in your activity's initialization async function handleReferral() { // Validate the referral data if (!discordSdk.customId || !discordSdk.referrerId) { return; } try { // Verify this is a valid promotion and hasn't expired const promotion = await validatePromotion(discordSdk.customId); if (!promotion) { console.log('Invalid or expired promotion'); return; } // Prevent self-referrals if (discordSdk.referrerId === currentUserId) { console.log('Self-referrals not allowed'); return; } // Grant rewards to both users await grantRewards({ promotionId: discordSdk.customId, referrerId: discordSdk.referrerId, newUserId: currentUserId }); } catch (error) { console.error('Failed to process referral:', error); } } ``` #### Link Sharing Best Practices * Generate unique, non-guessable `customId`s * Track and validate referrals to prevent abuse * Handle edge cases like expired promotions gracefully * Consider implementing cool-down periods between shares * Do not override the `referrer_id` query parameter directly. When present, `referrer_id` is expected to be a Discord snowflake-type user ID, otherwise it will be set to the message's author id. *** ## Creating and Managing Custom Incentivized Links This guide covers creating a customizable [Incentivized Link](/developers/activities/development-guides/growth-and-referrals#prompting-users-to-share-incentivized-links) through the dev portal, and then retrieving the link to be able to share it off-platform. Incentivized Links are used to customize how the embed appears to users. #### Creating a Link 1. In your Application's portal, visit the [Custom Links page](https://discord.com/developers/applications/select/embedded/custom-links) under the Activities heading in the navigation pane. 2. On the Custom Links page, click `Create New` to create a new link. 3. You will need to upload an image with an aspect ratio of 43:24. 4. Title, and description are also required. 5. `custom_id` is an optional field, an explicit `custom_id` query parameter on the link itself will always override the set `custom_id`. 6. Click Save. #### Editing a Link 1. Click on a row to open up the modal with all of the data loaded in ready for your edits. 2. Change the description to something else. 3. Click Update. #### Copying a Link Once you're satisfied with your changes you can click on the copy icon on the row, it'll change colors to green indicating that it copied to your clipboard. You are now able to share this link anywhere. The link will look like: `https://discord.com/activities/?link_id=0-123456789`. Even if you've set a `custom_id`, it won't be explicitly included in the link but will be loaded once a user clicks on the link. You can then further shorten this URL if you'd like. #### Deleting a Link 1. Click on the trash icon on the row of the link you're trying to delete. 2. You'll have a confirm dialog pop up. Deleting is irreversible and immediate. Ensure that your link isn't in active use before deleting and/or that your activity gracefully handles any click-throughs from the link. #### Best Practices * Generate unique, non-guessable `customId`s * Track and validate referrals to prevent abuse * Gracefully handle expirations in your activity for any custom links that are limited time but still live off-platform. #### User Experience custom-link-embed Users will see an embed with your information displayed. Clicking "Play" opens the activity and passes through the `custom_id` you've set. A `referrer_id` will be present for links shared on Discord. *** ## Generating a Custom Link Within Your Activity This guide covers creating a customizable [Incentivized Link](/developers/activities/development-guides/growth-and-referrals#prompting-users-to-share-incentivized-links) within your activity, and using the `shareLink` API to share the link. * Allows you to customize the way the link is presented to users via the embed * Can be generated on-demand within your activity * Ephemeral, 30 day TTL * Does not show up in the developer portal #### Generating a Link ```javascript theme={"system"} // Convert an image array buffer to base64 string const image = base64EncodedImage; // Generate the quick activity link const linkIdResponse = await fetch(`${env.discordAPI}/applications/${env.applicationId}/quick-links/`, { method: 'POST', headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json', }, body: { custom_id: 'user_123/game_456', description: 'I just beat level 10 with a perfect score', title: 'Check out my high score!', image, } }); const {link_id} = await linkIdResponse.json(); // Open the Share modal with the generated link const {success} = await discordSdk.commands.shareLink({ message: 'Check out my high score!', link_id, }); success ? console.log('User shared link!') : console.log('User did not share link!'); ``` # Layout Source: https://docs.discord.com/developers/activities/development-guides/layout Design effective layouts and user interfaces for Discord Activities. ## Application Orientation #### Locking Application Orientation This SDK provides APIs for locking the application to specific orientations. The possible lock states are `UNLOCKED`, `PORTRAIT`, and `LANDSCAPE`. `lock_state` is the default lock state, and it affects the app orientation when the application is focused. `picture_in_picture_lock_state` determines the PIP aspect ratio, and `grid_lock_state` determines the grid tile aspect ratio for the application. When `picture_in_picture_lock_state` is not set, the application PIP falls back to `lock_state` to determine the aspect ratio. When `grid_lock_state` is not set, the application grid tile falls back to `picture_in_picture_lock_state` to determine its aspect ratio, and if `picture_in_picture_lock_state`is not set, it uses `lock_state`. Calling `setOrientationLockState` with an `undefined` or omitted value for `picture_in_picture_lock_state` or `grid_lock_state` will not change the corresponding lock states for the application. Calling `setOrientationLockState` with a null value for `picture_in_picture_lock_state` or `grid_lock_state` will clear the application's corresponding lock states such that those layout modes will use the fallback lock states. ```javascript theme={"system"} import {DiscordSDK, Common} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(clientId); await discordSdk.ready(); // Set a default lock state discordSdk.commands.setOrientationLockState({lock_state: Common.OrientationLockStateTypeObject.LANDSCAPE}); // or set both a default lock state and a picture-in-picture lock state discordSdk.commands.setOrientationLockState({ lock_state: Common.OrientationLockStateTypeObject.PORTRAIT, picture_in_picture_lock_state: Common.OrientationLockStateTypeObject.LANDSCAPE, grid_lock_state: Common.OrientationLockStateTypeObject.LANDSCAPE, }); ``` #### Configuring Default Orientation Lock State Through the Developer Portal It's also possible to configure an application with a default orientation lock state via the Developer Portal. Using this method, the Discord app will apply the orientation lock when launching the application before the SDK has been initialized. This can create a smoother application launch flow where the application starts in the correct orientation rather than switching to the correct orientation after some delay after the application requests an orientation lock via the SDK. The Developer Portal supports setting a different default orientation lock states for phones versus tablets. default-orientation-lock-state #### Subscribing to Screen Orientation Updates To listen to the screen orientation (which is sometimes different from the physical device orientation), subscribe to the `ORIENTATION_UPDATE` event. Discord will publish the current orientation upon event subscription, and it'll also publish any orientation changes that happen afterward. ```javascript theme={"system"} const handleOrientationUpdate = (update: {screen_orientation: number}) => { switch (update.screen_orientation) { case Common.OrientationTypeObject.PORTRAIT: ... case Common.OrientationTypeObject.LANDSCAPE: ... default: ... } } discordSdk.subscribe('ORIENTATION_UPDATE', handleOrientationUpdate); ``` *** ## Application Layout Mode There are three layout modes that an application can be in: focused, picture-in-picture (PIP), or grid mode. Activities can subscribe to the layout mode to determine when to optionally change their layouts to optimize for each layout mode. Old Discord clients only support the `ACTIVITY_PIP_MODE_UPDATE` event, while new Discord clients support both `ACTIVITY_PIP_MODE_UPDATE` and `ACTIVITY_LAYOUT_MODE_UPDATE`. Use `subscribeToLayoutModeUpdatesCompat` and `unsubscribeFromLayoutModeUpdatesCompat` to subscribe to both events with backward compatibility for old Discord clients that only support `ACTIVITY_PIP_MODE_UPDATE`. Here's an example using React: ```javascript theme={"system"} export default function LayoutMode() { const handleLayoutModeUpdate = React.useCallback((update: {layout_mode: number}) => { ... }, []); React.useEffect(() => { discordSdk.subscribeToLayoutModeUpdatesCompat(handleLayoutModeUpdate); return () => { discordSdk.unsubscribeFromLayoutModeUpdatesCompat(handleLayoutModeUpdate); }; }, [handleLayoutModeUpdate]); } ``` # Local Development Source: https://docs.discord.com/developers/activities/development-guides/local-development Set up local development environment for Discord Activities. ## Run Your Application Locally It is possible to load your application via a localhost port or other unique URL. This URL must support an HTTPS connection to load on the web/desktop Discord app (HTTPS is not required for mobile). The downside to this flow is that your application's network traffic will not pass through Discord's proxy, which means any requests made by the application will need to use a full URL instead of a ["mapped"](/developers/activities/development-guides/local-development#url-mapping) URL. To run your locally hosted application, follow the instructions for [Launching your Application from the Discord Client](/developers/activities/development-guides/local-development#launch-your-application-from-the-discord-client) and set the Application URL Override to the address of your application's web server. ### Running Your Application Through A Network Tunnel Although it is possible to test your application locally, we recommend developing and testing against the Discord proxy. This is helpful to make sure all URLs behave as expected before your application runs in production. One technique to enable testing locally against the proxy is to use a network tunneling tool, such as [cloudflared](https://github.com/cloudflare/cloudflared#installing-cloudflared). A typical pattern is for each developer to have their own "development-only" application. To set up a local environment to run through Discord's proxy, you will need to do the following: 1. Create a new application in the Discord Developer portal. 2. Enable Activities for your app. 3. Set up the application's [URL mapping](/developers/activities/development-guides/local-development#url-mapping). 4. Locally, spin up your web server. 5. Install and run a tunnel solution, such as [cloudflared](https://github.com/cloudflare/cloudflared#installing-cloudflared). You will point it to your local web server. Your web server can be HTTP and your network tunnel can upgrade the connection to HTTPS. If using cloudflared, you will run the following command, replace `3000` with your web server's port. ``` cloudflared tunnel --url http://localhost:3000 ``` Once you run this command, you will receive your publicly accessible network tunnel address from cloudflared. ``` Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): https://funky-jogging-bunny.trycloudflare.com ``` In the Discord Developer Portal, update the Application URL mapping for `/` url to `funky-jogging-bunny.trycloudflare.com` to match your network tunnel address and save your changes. Configuring your URL Mapping If you do not own the URL that you are using to host the application (i.e. ngrok's free tier), someone else could claim that domain and host a malicious site in its place. Please be aware of these risks, and if you have to use a domain you do not own, be sure to reset your URL mapping when you are done using the tunnel. Follow the instructions for [Launching your Application from the Discord Client](/developers/activities/development-guides/local-development#launch-your-application-from-the-discord-client). Application URL Override should not be enabled. ### Running Your Application In Production The flow for setting up your production application is very similar: 1. If not made yet, create a new application. 2. Enable Activities for your app. 3. Set up the application's [URL Mapping](/developers/activities/development-guides/local-development#url-mapping). The URL for your application's html should be set to the `/` route. 4. Follow the instructions for [Launching your Application from the Discord Client](/developers/activities/development-guides/local-development#launch-your-application-from-the-discord-client). Application URL Override should not be enabled. This application now uses the same configuration it will use once it is fully published ✨. application-test-mode-prod *** ### Launch your application from the Discord Client You will be able to see and launch all activities owned by you or any teams you are a member of via the Developer Activity Shelf. One caveat is that the activity will not be shown on the current platform (web/ios/android) unless you have checked your platform in [Settings/Supported Platforms](https://discord.com/developers/applications/select/embedded/settings) on the developer portal. To see you app inside of Discord in the Activity Shelf: #### Web 1. Select ⚙️ User Settings > App Settings > Advanced and toggle on `Developer Mode` 2. Close the settings window and enter a voice channel. 3. From either the RTC Panel or the Center Control Tray, click on the "Rocket Button" to open the Activity shelf. You should now see all of the same applications that you have access to in the developer portal. Note: The shelf will only include applications which have been flagged as "Embedded". 4. Click on an activity to launch it! #### Mobile 1. From your User Profile, select Appearance, and then toggle "On" `Developer Mode` 2. Enter a voice channel 3. Click on an activity to launch it! *** ### URL Mapping Activities in Discord are "sandboxed" via a Discord proxy. This is done to hide the users' IP addresses, your application's IP addresses, and to block URLs from known malicious endpoints. As an application owner, you can configure the proxy to allow network requests to external endpoints. Because your application is "sandboxed", it will be unable to make network requests to external URLs. Let's say you want request `https://some-api.com`. To enable reaching this url from inside your application, you will create a new url mapping, with the `PREFIX` set to `/api` and `TARGET` set to `some-api.com`. Now you can make requests to `/api` from inside of your application, which will be forwarded, via Discord's proxy to `some-api.com`. #### How to set a URL Mapping To add or modify your application's URL mappings, click on [Activities -> URL Mappings](https://discord.com/developers/applications/select/embedded/url-mappings) and set the prefix and target values for each mapping as needed. Configuring your URL Mapping #### Prefix/Target formatting rules * URL mappings can utilize any url protocol, (https, wss, ftp, etc...), which is why the URL target should not include a protocol. For example, for a URL target, do not put `https://your-url.com`, instead, omit `https://` and use `your-url.com`. * Parameter matching can be used to help map external domain urls. For example, if an external url has many subdomains, such as `foo.google.com`, `bar.google.com`, then you could use the following mapping: | PREFIX | TARGET | | --------------------- | ------------------------ | | `/google/{subdomain}` | `{subdomain}.google.com` | * Targets must point to a directory; setting a target to a file (e.g. `example.com/index.html`) is unsupported and may lead to unexpected behavior. * Because of how URL globbing works, if you have multiple prefix urls with the same initial path, you must place the shortest of the prefix paths last in order for each url mapping to be reachable. For example, if you have `/foo` and `/foo/bar`, you must place the url `/foo/bar` before `/foo` or else the mapping for `/foo/bar` will never be reached. | ✅ DO | ❌ DON'T | | -------------------------------- | ---------------------------------------------------------- | | Requests mapped correctly | Requests to /foo/bar will incorrectly be sent to `foo.com` | | url-mapping-do.png | url-mapping-dont.png | #### Exceptions The aforementioned "sandbox" is enforced by a [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP). We have some notable exceptions to our CSP, meaning application clients may make requests to these URLs without hitting the proxy and therefore without establishing mappings. Notable exceptions include: * `https://discord.com/api/` * `https://canary.discord.com/api/` * `https://ptb.discord.com/api/` * `https://cdn.discordapp.com/attachments/` * `https://cdn.discordapp.com/avatars/` * `https://cdn.discordapp.com/icons/` * `https://media.discordapp.net/attachments/` * `https://media.discordapp.net/avatars/` * `https://media.discordapp.net/icons/` *** ### Logging By default, the SDK will send any console `log`, `warn`, `error`, `info`, and `debug` events triggered by your app to the Discord application. #### Viewing Logs on Desktop Desktop logs are viewable through the console tab inside a browser's Developer Tools. See the [Troubleshooting Console Log Errors](https://support.discord.com/hc/en-us/articles/115001239472-Troubleshooting-Console-Log-Errors) support article for more information. The Public Test Build (PTB) Discord client also allows inspecting your logs from the `View -> Developer -> Toggle Developer Tools` menu. It can be downloaded at [https://discord.com/downloads](https://discord.com/downloads). #### Viewing Logs on Mobile Mobile logs are viewable via the `Debug Logs` option inside User Settings on the mobile App. It is only discoverable when you have `Developer Mode` enabled. 1. On the bottom navigation, tap on your avatar and then the gear icon to open your `User Settings`. 2. Tap `Appearance`. 3. Slide the `Developer Mode` toggle to ON. 4. The `Debug Logs` option will be available under the `DEV ONLY` section. #### Filtering for Application Logs Inside the Debug Logs view, you can search for your own application logs with the possible keywords: * `RpcApplicationLogger` * Your Application ID Each log line is formatted as: `[RpcApplicationLogger] - message` The first section of Debug Logs are not your application logs but Discord specific app startup info which is not relevant to your application. When you scroll down the page, your application logs should be visible. debug-logs-filtering #### Sharing Application Logs from Mobile With `Developer Mode` enabled, you can share your application logs from within a Voice Channel. 1. In the voice channel, swipe from the bottom to see the expanded voice controls. Tap on `Share Application Logs`. 2. You'll be presented with a native share sheet where you can save the logs to a file or share it as a message. #### Disabling Logging If you do not want logs to be forwarded to the browser, you can disable it with the optional configuration object. ```javascript theme={"system"} import {DiscordSDK} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(clientId, { disableConsoleLogOverride: true, }); ``` #### Forwarding Log Messages You can forward specific log messages via the SDK command `captureLog` as shown below. ```javascript theme={"system"} import {DiscordSDK} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(clientId); await discordSdk.ready(); discordSdk.commands.captureLog({ level: 'log', message: 'This is my log message!', }); ``` # Mobile Source: https://docs.discord.com/developers/activities/development-guides/mobile Design and optimize Discord Activities for mobile devices. ## Supported Platforms: Web, iOS, Android By default, your Activity will be launchable on web/desktop. To enable or disable support for Web/iOS/Android, do the following: * Visit the [developer portal](https://discord.com/developers/applications) * Select your application * Select [Activities -> Settings](https://discord.com/developers/applications/select/embedded/settings) in the left-side of the developer portal * From check the appropriate checkboxes in the developer portal, and save your changes supported-platforms *** ## Mobile Safe Areas As an example, you can define your safe area insets as below in CSS: ```css theme={"system"} :root { --sait: var(--discord-safe-area-inset-top, env(safe-area-inset-top)); --saib: var(--discord-safe-area-inset-bottom, env(safe-area-inset-bottom)); --sail: var(--discord-safe-area-inset-left, env(safe-area-inset-left)); --sair: var(--discord-safe-area-inset-right, env(safe-area-inset-right)); } ``` This prefers the `--discord-safe-area-inset-*` variable and will fallback to the env values for iOS + any local dev testing that is done outside of Discord. You can then reference these values: ```css theme={"system"} body { padding-left: var(--sail); padding-right: var(--sair); padding-top: var(--sait); padding-bottom: var(--saib); } ``` *** ## Mobile Thermal States You may need to respond to thermal state changes using recommendations from [thermal states surfaced by mobile devices](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/RespondToThermalStateChanges.html) to improve the user experience. Discord's Embedded App SDK provides an abstraction over [Apple's thermal state APIs](https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/RespondToThermalStateChanges.html) and [Android's thermal state APIs](https://source.android.com/docs/core/power/thermal-mitigation#thermal-api). Here's how Discord's abstraction maps to Apple's thermal states and Android's thermal states. ```javascript theme={"system"} enum ThermalState { NOMINAL = 0, // maps to "nominal" on iOS and "none" on Android FAIR = 1, // maps to "fair" on iOS and "light" / "moderate" on Android SERIOUS = 2, // maps to "serious" on iOS and "severe" on Android CRITICAL = 3, // maps to "critical" on iOS and "critical" / "emergency" / "shutdown" on Android } ``` The Embedded App SDK allows developers to subscribe to these thermal state changes. ```javascript theme={"system"} const handleThermalStateUpdate = (update: {thermal_state: number}) => { switch (thermalState) { case Common.ThermalStateTypeObject.NOMINAL: ... case Common.ThermalStateTypeObject.FAIR: ... case Common.ThermalStateTypeObject.SERIOUS: ... case Common.ThermalStateTypeObject.CRITICAL: ... default: ... } } discordSdk.subscribe('THERMAL_STATE_UPDATE', handleThermalStateUpdate); ``` Discord will publish the current thermal state upon event subscription, and it will also publish any thermal state changes that happen afterward. On Android devices, the thermal state updates will only be available on Android 10 and higher. # Multiplayer Experience Source: https://docs.discord.com/developers/activities/development-guides/multiplayer-experience Design and implement engaging multiplayer experiences in Discord Activities. ## Activity Instance Management When a user clicks "Join Application", they expect to enter the same application that their friends are participating in. Whether the application is a shared drawing canvas, board game, collaborative playlist, or first-person shooter; the two users should have access to the same shared data. In this documentation, we refer to this shared data as an **application instance**. join-application The Embedded App SDK allows your app to talk bidirectionally with the Discord Client. The `instanceId` is necessary for your application, as well as Discord, to understand which unique instance of an application it is talking to. #### Using instanceId The `instanceId` attribute is available as soon as the SDK is constructed, and does not require the SDK to receive a `ready` payload from the Discord client. ```javascript theme={"system"} import {DiscordSDK} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(clientId); // available immediately const instanceId = discordSdk.instanceId; ``` The `instanceId` should be used as a key to save and load the shared data relevant to an application. This ensures that two users who are in the same application instance have access to the same shared data. ##### Semantics of instanceId Instance IDs are generated when a user launches an application. Any users joining the same application will receive the same `instanceId`. When all the users of an application in a channel leave or close the application, that instance has finished its lifecycle, and will not be used again. The next time a user opens the application in that channel, a new `instanceId` will be generated. *** ## Instance Participants Instance Participants are any Discord user actively connected to the same Application Instance. This data can be fetched or subscribed to. ```javascript theme={"system"} import {DiscordSDK, Events, type Types} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK('...'); await discordSdk.ready(); // Fetch const participants = await discordSdk.commands.getInstanceConnectedParticipants(); // Subscribe function updateParticipants(participants: Types.GetActivityInstanceConnectedParticipantsResponse) { // Do something really cool } discordSdk.subscribe(Events.ACTIVITY_INSTANCE_PARTICIPANTS_UPDATE, updateParticipants); // Unsubscribe discordSdk.unsubscribe(Events.ACTIVITY_INSTANCE_PARTICIPANTS_UPDATE, updateParticipants); ``` *** ## Render Avatars and Names Check out detailed documentation on where and how Discord stores common image assets [here](/developers/reference#image-formatting-cdn-endpoints). Here's a basic example for retrieving a user's avatar and username ```javascript theme={"system"} // We'll be referencing the user object returned from authenticate const {user} = await discordSdk.commands.authenticate({ access_token: accessToken, }); let avatarSrc = ''; if (user.avatar) { avatarSrc = `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=256`; } else { const defaultAvatarIndex = (BigInt(user.id) >> 22n) % 6n; avatarSrc = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarIndex}.png` } const username = user.global_name ?? `${user.username}#${user.discriminator}`; // Then in your HTML/JSX/etc... avatar

{username}

``` #### Rendering guild-specific avatars and nicknames In order to retrieve a user's guild-specific avatar and nickname, your application must request the `guilds.members.read` scope. Note, this only grants the information for that instance of the application's user. To display the guild-specific avatar/nickname for all application users, any info retrieved from `guilds.members.read` scope'd API calls must be shared via your application's server. Here's an example of how to retrieve the user's guild-specific avatar and nickname: ```javascript theme={"system"} // We'll be referencing the user object returned from authenticate const {user} = await discordSdk.commands.authenticate({ access_token: accessToken, }); // When using the proxy, you may instead replace `https://discord.com` with `/discord` // or whatever url mapping you have chosen via the developer portal fetch(`https://discord.com/api/users/@me/guilds/${discordSdk.guildId}/member`, { method: 'GET', headers: { Authorization: `Bearer ${accessToken}`, }, }) .then((response) => { return response.json(); }) .then((guildsMembersRead) => { let guildAvatarSrc = ''; // Retrieve the guild-specific avatar, and fallback to the user's avatar if (guildsMembersRead?.avatar) { guildAvatarSrc = `https://cdn.discordapp.com/guilds/${discordSdk.guildId}/users/${user.id}/avatars/${guildsMembersRead.avatar}.png?size=256`; } else if (user.avatar) { guildAvatarSrc = `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=256`; } else { const defaultAvatarIndex = (BigInt(user.id) >> 22n) % 6n; avatarSrc = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarIndex}.png`; } // Retrieve the guild-specific nickname, and fallback to the username#discriminator const guildNickname = guildsMembersRead?.nick ?? (user.global_name ?? `${user.username}#${user.discriminator}`); }); ``` This example is being done entirely on the client, however, a more common pattern is to instead, do the following: * Store the user's access token on the application server * Retrieve the user's guild-specific avatar and nickname via the application's server * Serve all of the application's avatar/nicknames via the application's server *** ## Preventing unwanted activity sessions Activities are surfaced through iframes in the Discord app. The activity website itself is publicly reachable at `.discordsays.com`. Activities will expect to be able to communicate with Discord's web or mobile client via the Discord SDK's RPC protocol. If a user loads the activity's website in a normal browser, the Discord RPC server will not be present, and the activity will likely fail in some way. It is theoretically possible for a malicious client to mock Discord's RPC protocol or load one activity website when launching another. Because the activity is loaded inside Discord, the RPC protocol is active, and the activity is none the wiser. ### Using the Activity Instance API To enable an activity to "lock down" activity access, we encourage utilizing the `get_activity_instance` API, found at `discord.com/api/applications//activity-instances/'`. The route requires a Bot token of the application. It returns a serialized active activity instance for the given application, if found, otherwise it returns a 404. Here are two example responses: ```javascript theme={"system"} curl https://discord.com/api/applications/1215413995645968394/activity-instances/i-1234567890-gc-912952092627435520-912954213460484116 -H 'Authorization: Bot ' {"message": "404: Not Found", "code": 0} curl https://discord.com/api/applications/1215413995645968394/activity-instances/i-1276580072400224306-gc-912952092627435520-912954213460484116 -H 'Authorization: Bot ' {"application_id":"1215413995645968394","instance_id":"i-1276580072400224306-gc-912952092627435520-912954213460484116","launch_id":"1276580072400224306","location":{"id":"gc-912952092627435520-912954213460484116","kind":"gc","channel_id":"912954213460484116","guild_id":"912952092627435520"},"users":["205519959982473217"]} ``` With this API, the activity's backend can verify that a client is in fact in an instance of that activity before allowing the client to participate in any meaningful gameplay. How an activity implements "session verification" is left to the developer's discretion. The solution can be as granular as gating specific features or as binary as not returning the activity HTML except for valid sessions. ###### Validating Proxy Request Headers For apps that want additional security validation, Discord provides an optional proxy authentication system. When your embedded app makes requests through Discord's proxy, each request can include cryptographic headers that prove the request's authenticity. Each proxy-authenticated request is sent with the following headers: * `X-Signature-Ed25519` as a cryptographic signature * `X-Signature-Timestamp` as a Unix timestamp * `X-Discord-Proxy-Payload` as a base64-encoded payload containing user context If you choose to use proxy authentication, you can validate these headers to ensure requests are legitimate. If the signature fails validation, your app should respond with a `401` error code. Below are some code examples that show how to validate the headers sent in proxy-authenticated requests. **JavaScript** ```js theme={"system"} const nacl = require("tweetnacl"); // Your public key can be found on your application in the Developer Portal const PUBLIC_KEY = "APPLICATION_PUBLIC_KEY"; const signature = req.get("X-Signature-Ed25519"); const timestamp = req.get("X-Signature-Timestamp"); const payload = req.get("X-Discord-Proxy-Payload"); // Decode the base64 payload const payloadBytes = Buffer.from(payload, "base64"); const payloadString = payloadBytes.toString("utf-8"); const payloadData = JSON.parse(payloadString); // Verify timestamp matches payload if (payloadData.created_at.toString() !== timestamp) { return res.status(401).end("invalid request timestamp"); } // Check if token has expired if (payloadData.expires_at < Math.floor(Date.now() / 1000)) { return res.status(401).end("expired proxy token"); } // Verify the signature using tweetnacl const isVerified = nacl.sign.detached.verify( payloadBytes, Buffer.from(signature, "base64"), Buffer.from(PUBLIC_KEY, "hex") ); if (!isVerified) { return res.status(401).end("invalid request signature"); } ``` **Python** ```py theme={"system"} import json import base64 import time from nacl.signing import VerifyKey from nacl.exceptions import BadSignatureError # Your public key can be found on your application in the Developer Portal PUBLIC_KEY = 'APPLICATION_PUBLIC_KEY' verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY)) signature = request.headers["X-Signature-Ed25519"] timestamp = request.headers["X-Signature-Timestamp"] payload = request.headers["X-Discord-Proxy-Payload"] # Decode the base64 payload payload_bytes = base64.b64decode(payload) payload_string = payload_bytes.decode('utf-8') payload_data = json.loads(payload_string) # Verify timestamp matches payload if str(payload_data['created_at']) != timestamp: abort(401, 'invalid request timestamp') # Check if token has expired if payload_data['expires_at'] < int(time.time()): abort(401, 'expired proxy token') try: verify_key.verify(payload_bytes, bytes.fromhex(signature)) except BadSignatureError: abort(401, 'invalid request signature') ``` Proxy authentication is entirely optional and provided as an additional security layer for apps that choose to implement it. In the below flow diagram, we show how the server can deliver the activity website, only for valid users in a valid activity instance: activity-instance-validation # Networking Source: https://docs.discord.com/developers/activities/development-guides/networking Learn networking patterns and best practices for Discord Activities. ## Activity Proxy Considerations All network traffic is routed through the Discord Proxy for various security reasons. Under the hood we utilize Cloudflare Workers, which brings some restrictions, outlined below. #### WebTransport While we currently only support websockets, we're working with our upstream providers to enable WebTransport. #### WebRTC WebRTC is not supported. *** ## Construct A Full URL There are scenarios where instead of using a relative url (`/path/to/my/thing`) you may want or need to reference the full url when making a network request. The URL is a combination of the following 1. The protocol you wish to use 2. Your application's client id 3. The discord proxy domain 4. Whatever you need to list Here's an example of how to build a full url, using the URL constructor: ```javascript theme={"system"} const protocol = `https`; const clientId = ''; const proxyDomain = 'discordsays.com'; const resourcePath = '/foo/bar.jpg'; const url = new URL(`${protocol}://${clientId}.${proxyDomain}${resourcePath}`); ``` In other words, given an application client id of `12345678` | Relative Path | Full Path | | ------------- | -------------------------------------------------------------------------------------------- | | /foo/bar.jpg | [https://12345678.discordsays.com/foo/bar.jpg](https://12345678.discordsays.com/foo/bar.jpg) | *** ## Using External Resources Activities in Discord are "sandboxed" via a Discord proxy. This is done to hide the users' IP addresses as well as block URLs from known malicious endpoints. To achieve this, the Discord Developer Portal has a section for [configuring URL Mappings](/developers/activities/development-guides/local-development#url-mapping) for your application. One edge-case of URL mappings is that third-party NPM modules or other resources may reference external (non-sandboxed) urls. For example, if your application has an npm module that attempts to make an http request to [https://foo.library.com](https://foo.library.com), the request will fail with a `blocked:csp` error. To get around this limitation there are several options to consider: * Fork the library (to use mapped urls) * Utilize a post-install utility such as [patch-package](https://www.npmjs.com/package/patch-package) * Use our Embedded App SDK's `patchUrlMappings` API In the above scenario, we recommend using the `patchUrlMappings` API, as it will allow a smooth transition from the non-sandboxed dev environment to the production environment. This method call takes an array of "mappings" which will transform any external network requests to the mappings you've defined. See the example below: * In this example, imagine you have a third-party library which makes an HTTP request to foo.com * In the developer portal, create a mapping like this: `/foo` -> `foo.com` * Then in your code, when initializing the SDK, you will make a function call. ```javascript theme={"system"} import {patchUrlMappings} from '@discord/embedded-app-sdk'; const isProd = process.env.NODE_ENV === 'production'; // Actual dev/prod env check may vary for you async function setupApp() { if (isProd) { patchUrlMappings([{prefix: '/foo', target: 'foo.com'}]); } // start app initialization after this.... } ``` Note: `patchUrlMappings` is modifying your browser's `fetch`, `WebSocket`, and `XMLHttpRequest.prototype.open` global variables. Depending on the library, you may see side effects from using this helper function. It should be used only when necessary. *** ## Security Considerations #### Trusting Client Data Do not trust data coming from the Discord client as truth. It's fine to use this data in your application locally, but assume any data coming from the Discord Client could be falsified. That includes data about the current user, their nitro status, their current channel, etc. If you need this information in a trusted manner, contact Discord API directly from your application's server, with the user token you received from completing the OAuth2 flow. Furthermore, data coming from the Discord client is not sanitized beforehand. Things like usernames and channel names are arbitrary user input. Make sure to sanitize these strings or use `.textContent` (for example) to display them safely in your UI. #### Using Cookies To set a cookie for your activity to use in network requests through the proxy, make sure the cookie's domain matches your app's full `{clientId}.discordsays.com` domain. You will also need to explicitly set `SameSite=None Partitioned` on the cookie. `SameSite=None` is needed as browsers refuse to store or send cookies with higher restriction levels for any navigation within an iframe. `Partitioned` then limits the use of that cookie to only Discord's iframes. Rest assured: other activities will not be able to make requests with your activity's cookie, thanks to the Content Security Policy (CSP) limiting requests only to your own app's proxy. # Production Readiness Source: https://docs.discord.com/developers/activities/development-guides/production-readiness Prepare your Discord Activity for production deployment. ## Cache Busting All assets loaded by your application will respect [cache headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control). One exception is that Discord's application proxy will remove any cache headers for assets whose `content-type` headers include `text/html`. For all non-`text/html` content that your application plans to serve, be sure your application has a cache-busting strategy. This is often built into build processes. If your application has a static filename for its javascript or css, please be sure to implement cache busting techniques, for example [webpack enables creating dynamic file names](https://webpack.js.org/guides/caching/). *** ## Handling Rate Limits Be sure network requests made by your application's client and server will be able to respect Discord API's rate limiting [as described here](/developers/topics/rate-limits). See [this implementation in the Activity Starter project](https://github.com/discord/embedded-app-sdk-examples/blob/main/discord-activity-starter/packages/server/src/utils.ts) for an example of how to respect the `retry_after` header when you receive a 429 error. *** ## Static IP Addresses If your application's server is utilizing a dynamically assigned IP address (this is standard for cloud functions), there is a non-zero chance that you will inherit from a previous bad actor an IP address which has been banned by Cloudflare. In this scenario any egress traffic from the IP address directed towards Discord's API will be banned for up-to an hour. The best way to mitigate this situation is to set up a static IP address for all of your application server's egress traffic to be routed through. *** ## Backward Compatibility #### New Commands When new commands become available in the embedded-app-sdk, those commands won't be supported by all Discord app versions. The new command will typically only be supported by newer Discord app versions. When an application tries to use a new command with an old Discord app version that doesn't support the command, the Discord app will respond with error code `INVALID_COMMAND` which the application can handle like this: ```javascript theme={"system"} try { const {permissions} = await discordSdk.commands.getChannelPermissions(); // check permissions ... } catch (error) { if (error.code == RPCErrorCodes.INVALID_COMMAND) { // This is an expected error. The Discord client doesn't support this command ... } else { // Unexpected error ... } } ``` # User Actions Source: https://docs.discord.com/developers/activities/development-guides/user-actions Implement user interactions and actions in Discord Activities. ## Open External Link Since Activities are sandboxed, your app will need to perform a command in order for users to launch any external links. Users will be prompted inside Discord whether or not they want to open the external link. #### Usage ```javascript theme={"system"} import {DiscordSDK} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(clientId); await discordSdk.ready(); // Once the sdk has established the connection with the discord client, external // links can be launched discordSdk.commands.openExternalLink({ url: 'https://google.com', }); ``` #### User Experience external-link-modal Users will see a modal inside the Discord app notifying them whether or not they want to proceed. By clicking ***Trust this Domain***, users will not see a modal for that specific domain again. *** ## Open Invite Dialog Getting an Application Channel Invite, as outlined in [these docs](/developers/resources/invite#get-invite), is not granted by any OAuth scopes. Nonetheless, the `openInviteDialog` command is available via the SDK. This command opens the Application Channel Invite UI within the discord client without requiring additional OAuth scopes. This command returns an error when called from DM (Direct Message) contexts, so should only be called in Guild Voice or Text Channels. Similarly, this command returns an error if the user has invalid permissions for the channel, so using `getChannelPermissions` (requires OAuth scope `'guilds.members.read'`) is highly recommended. #### Usage ```javascript theme={"system"} import {DiscordSDK, Permissions, PermissionUtils} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(clientId); await discordSdk.ready(); try { const {permissions} = await discordSdk.commands.getChannelPermissions(); if (PermissionUtils.can(Permissions.CREATE_INSTANT_INVITE, permissions)) { await discordSdk.commands.openInviteDialog(); // successfully opened dialog } else { console.warn('User does not have CREATE_INSTANT_INVITE permissions'); } } catch (err) { // failed to fetch permissions or open dialog console.warn(err.message); } ``` User Experience Invite Dialog UI Users will see a modal inside the Discord app allowing them to send an invite to a channel, friend, or copy an invite link to share manually. *** ## Open Share Moment Dialog The easiest way for an application to share media to a channel or DM is to use the `openShareMomentDialog` command. This command accepts a Discord CDN `mediaUrl` (eg `https://cdn.discordapp.com/attachments/...`) and opens a dialog on the discord client that allows the user to select channels, DMs, and GDMs to share to. This requires no additional OAuth scopes, but does require the application to be authenticated. Since `mediaUrl` must be a Discord CDN URL, it is encouraged to use the activities attachment API endpoint (`discord.com/api/applications/${applicationId}/attachment`) to create an ephemeral CDN URL. This endpoint accepts bearer tokens for any scopes, so it can be called from the application client using the authorized user's bearer token. The endpoint returns a serialized attachment, which includes a `url` attribute, which should then be passed to the DiscordSDK command as `mediaUrl`. #### Usage ```javascript theme={"system"} import {discordSdk} from './wherever-you-initialize-your-sdk'; import {accessToken} from './wherever-you-store-your-access-token'; // some image const imageURL = 'https://i.imgur.com/vaSWuKr.gif'; // get image data const response = await fetch(imageURL); const blob = await response.blob(); const mimeType = blob.type; // image data as buffer const buf = await blob.arrayBuffer(); // image as file const imageFile = new File([buf], 'example.gif', {type: mimeType}); const body = new FormData(); body.append('file', imageFile); const attachmentResponse = await fetch(`${env.discordAPI}/applications/${env.applicationId}/attachment`, { method: 'POST', headers: { Authorization: `Bearer ${accessToken}`, }, body, }); const attachmentJson = await attachmentResponse.json(); // mediaUrl is an ephemeral Discord CDN URL const mediaUrl = attachmentJson.attachment.url; // opens dialog in Discord client await discordSdk.commands.openShareMomentDialog({mediaUrl}); ``` User Experience Example of the sharing dialog *** ## Setting Up an Entry Point Command An [Entry Point command](/developers/interactions/application-commands#entry-point-commands) is required for users to be able to launch your Activity from the [App Launcher menu](https://support.discord.com/hc/articles/21334461140375-Using-Apps-on-Discord#h_01HRQSA6C8TRHS722P1H3HW1TV) in Discord. When you enable Activities in your [app's settings](http://discord.com/developers/applications), a [default Entry Point command](/developers/interactions/application-commands#default-entry-point-command) is automatically created for your app. The default Entry Point command will use the `DISCORD_LAUNCH_ACTIVITY` (`2`) [handler type](/developers/interactions/application-commands#application-command-object-entry-point-command-handler-types), which means that Discord automatically launches your Activity for the user and posts a follow-up message into the channel where it was launched from. If you want to handle sending messages yourself, you can update the handler to be `APP_HANDLER` (`1`). Details about Entry Point command handlers is in the [Entry Point command documentation](/developers/interactions/application-commands#entry-point-handlers). #### Customizing the Default Entry Point Command Entry Point commands can be customized in the same way as other [commands](/developers/interactions/application-commands). Since Entry Point commands can only be [global](/developers/interactions/application-commands#making-a-global-command), you'll use the HTTP endpoints for global commands: * **Edit your existing Entry Point command's name or details** using the [Edit Global Application Command](/developers/interactions/application-commands#edit-global-application-command) endpoint. If you don't know the ID for your app's Entry Point command, use the [Get Global Application Commands](/developers/interactions/application-commands#get-global-application-commands) endpoint to retrieve it. * **Make a different (option-less) command your Entry Point command** by updating its [command `type`](/developers/interactions/application-commands#application-command-object-application-command-types) to `PRIMARY_ENTRY_POINT` (type `4`). Your app can only have one Entry Point command, so if your app already has one, you must first [delete](/developers/interactions/application-commands#delete-global-application-command) it or [update](/developers/interactions/application-commands#edit-global-application-command) its [command `type`](/developers/interactions/application-commands#application-command-object-application-command-types). #### Creating an Entry Point Command To create a new Entry Point command, you can call the [Create Global Application Command](/developers/interactions/application-commands#create-global-application-command) endpoint and set the [command `type`](/developers/interactions/application-commands#application-command-object-application-command-types) to `PRIMARY_ENTRY_POINT` (type `4`). Your command payload may look something like this: ```json theme={"system"} { "name": "launch", "description": "Launch Realms of Wumpus", // PRIMARY_ENTRY_POINT is type 4 "type": 4, // DISCORD_LAUNCH_ACTIVITY is handler value 2 "handler": 2, // integration_types and contexts define where your command can be used (see below) "integration_types": [0, 1], "contexts": [0, 1, 2] } ``` In addition to the `type` and `handler` values, the command payload includes `integration_types` and `contexts` which let you configure when and where your command can be used: * `integration_types` defines the [installation contexts](/developers/resources/application#installation-context) where your command is available (to a server, to a user's account, or both). If you don't set `integration_types` when creating a command, it will default to your app's [currently-supported installation contexts](/developers/resources/application#setting-supported-installation-contexts). * `contexts` defines the [interaction contexts](/developers/interactions/receiving-and-responding#interaction-object-interaction-context-types) where a command can be run in Discord (in a server, in a DM with your app, and/or in DMs and Group DMs with other users). Details about both of these fields are in the [command contexts](/developers/interactions/application-commands#contexts) documentation. *** ## Encourage Hardware Acceleration Activities that are compute intensive may benefit from encouraging users to enable hardware acceleration. When an application invokes the `encourageHardwareAcceleration` command the current status of the setting will be returned and the user will be prompted to update the setting, if applicable. Users will see a modal inside the Discord app if Hardware Acceleration is disabled, encouraging them to change the setting. By clicking **Don't show me this again** they will not see the modal for *any application* on this device again. #### Best Practices Switching the Hardware Acceleration setting causes the Discord client to quit and re-launch, so it is best practice to invoke this command as soon as possible, so users do not begin the experience of an application before restarting. Ideally, this is immediately after `await discordSdk.ready()`. #### Usage ```javascript theme={"system"} import {DiscordSDK} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(clientId); await discordSdk.ready(); const {enabled} = await discordSdk.commands.encourageHardwareAcceleration(); console.log(`Hardware Acceleration is ${enabled === true ? 'enabled' : 'disabled'}`); ``` #### User Experience encourage-hardware-acceleration-modal # How Activities Work Source: https://docs.discord.com/developers/activities/how-activities-work Understand the technical architecture and lifecycle of Discord Activities. Activities are web applications that run in an iframe within Discord on desktop, mobile and web. In order to achieve this, we use the [`postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) protocol to enable secure communication between your application and Discord. The [Embedded App SDK](https://github.com/discord/embedded-app-sdk) simplifies this process by managing the `postMessage` protocol on your behalf. For details on available commands and their usage, consult the [SDK Reference](/developers/developer-tools/embedded-app-sdk). Our [Sample Projects](/developers/activities/overview#sample-projects) provide practical examples of how to implement these features. ## Launching Activities After you have Activities enabled in your Application's [Activity's settings](https://discord.com/developers/applications/select/embedded/settings), your app can launch Activities in two ways: 1. When a user invokes your app's Entry Point command in the App Launcher 2. By responding to an interaction with the `LAUNCH_ACTIVITY` callback type Each of these are covered in more detail in the below sections. ### Entry Point Command Activities are primarily opened when users invoke your app's [Entry Point command](/developers/interactions/application-commands#entry-point-commands) in the App Launcher. When you enable Activities for your app, a [default Entry Point command](/developers/interactions/application-commands#default-entry-point-command) called "Launch" is created for you. By default, Discord automatically handles opening your Activity when your Entry Point command is run by a user. Read more about setting up Entry Point commands in the [development guide](/developers/activities/development-guides/user-actions#setting-up-an-entry-point-command). ### Interaction Response Activities can be launched in response to [command](/developers/interactions/overview#commands), [message component](/developers/interactions/overview#message-components), and [modal submission](/developers/interactions/overview#modals) interactions. To open an Activity, set the callback type to `LAUNCH_ACTIVITY` (type `12`) when [responding to the interaction](/developers/interactions/receiving-and-responding#responding-to-an-interaction). *** ## Designed for Single-Page Apps (SPAs) This SDK is intended for use by a single-page application. We recognize developers may be using frameworks or approaches that are not an exact fit for single-page applications. We recommend nesting those frameworks inside your Activity's top-level single-page application and passing messages as you see fit. Please refer to the [Nested Messages App](/developers/activities/overview#sample-projects) sample project for guidance on this approach. ## Activity Lifecycle 1. **Initialization:** When your iframe is loaded within Discord, it will include unique query parameters in its URL. These parameters are identifiable by your application using the Discord SDK. 2. **Handshake Process:** Constructing the SDK instance begins a handshake process with the Discord client. Once the connection is established, the iframe receives a `[FRAME, {evt: 'READY', ...}]` message. The `ready()` method of the SDK instance resolves once a successful connection has been established. 3. **Authorization and Authentication:** After receiving the `READY` payload, your application should perform authorization and authentication to acquire necessary permissions (scopes). This step is crucial for utilizing specific features or scopes, such as `rpc.activities.write`. 4. **Interacting with Discord Client:** Post-authentication, your application can subscribe to events and send commands to the Discord client. Note that attempting to use commands or subscribe to events outside your granted scope will result in errors. Adding new scopes may prompt an OAuth modal for user permission re-confirmation. 5. **Disconnection and Errors:** Receiving a `[CLOSE, {message: string, code: number}]` message indicates an error or a need to restart the connection process. 6. **Sending Errors or Close Requests:** To communicate an error or request a close from the Discord client, send `[CLOSE, {message?: string, code: number}]`. A code other than CLOSE\_NORMAL will display the message to the user, while CLOSE\_NORMAL results in a silent closure. ## Sample Code and Activity Lifecycle Diagram Below is a minimal example of setting up the SDK. Please see our [Sample Projects](/developers/activities/overview#sample-projects) for more complete sample applications. ```javascript theme={"system"} import {DiscordSDK} from '@discord/embedded-app-sdk'; const discordSdk = new DiscordSDK(YOUR_OAUTH2_CLIENT_ID); async function setup() { // Wait for READY payload from the discord client await discordSdk.ready(); // Pop open the OAuth permission modal and request for access to scopes listed in scope array below const {code} = await discordSdk.commands.authorize({ client_id: YOUR_OAUTH2_CLIENT_ID, response_type: 'code', state: '', prompt: 'none', scope: ['identify'], }); // Retrieve an access_token from your application's server const response = await fetch('/.proxy/api/token', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ code, }), }); const {access_token} = await response.json(); // Authenticate with Discord client (using the access_token) auth = await discordSdk.commands.authenticate({ access_token, }); } ``` This diagram illustrates the communication flow between your application and Discord in the sample code above. Diagram of how Activities communicate with Discord # Activities Overview Source: https://docs.discord.com/developers/activities/overview Learn about Discord Activities - multiplayer games and social experiences. Building Discord Activities Activities are web apps hosted in an iframe that use the [Embedded App SDK](/developers/activities/overview#embedded-app-sdk) to communicate with Discord clients. For an introduction to what Activities are, see the [Activities](/developers/platform/activities) platform page. This section covers how Activities are built. You can explore real-world Activities by reading some of our [developer case studies](https://discord.com/build#case-studies), or jump right into building using the resources below. Follow the guide to build your first Activity using the Embedded App SDK. Explore common development patterns and practices to make building Activities simpler. Learn more about the lifecycle of Activities and how they run in Discord clients. *** ## Developing Activities Whether you're developing a multiplayer game, a new social experience, or another creative idea, your Activity will be built as a web app that is run in an iframe in Discord on desktop, mobile, and web. You can get started by following the guide on [Building an Activity using the Embedded App SDK](/developers/activities/building-an-activity) or exploring the [sample projects](/developers/activities/overview#sample-projects) The sections below provide an overview of the Embedded App SDK, but technical details about how Activities are run in Discord is covered in [How Activities Work](/developers/activities/how-activities-work). ### Embedded App SDK The [Embedded App SDK](/developers/developer-tools/embedded-app-sdk) handles all of the communication between Discord and your app, making it easier to do common tasks like managing connected users, supporting mobile clients, and debugging your Activity. The Embedded App SDK offers different events and commands to handle the communication between Discord and your Activity, which are covered more below. #### Commands The SDK has a set of commands you can call to interact with a Discord client, given you have the appropriate scopes. This is helpful when you want to do authorize and authenticate users, fetch information about your Activity, or update information for your Activity or an authenticated user. Read the [Embedded App SDK documentation](/developers/developer-tools/embedded-app-sdk#sdk-commands) for a full list of commands, and details about each command. #### Events The SDK also has events you can subscribe (or unsubscribe) to for things happening in a connected client that are relevant to your Activity, given you have the appropriate scopes. This is helpful when you want to do things like handle initial connection and thrown errors, listen to updates about a connected user, and listen to events related to your Activity instance. Read the [Embedded App SDK documentation](/developers/developer-tools/embedded-app-sdk#sdk-events) for a full list of events, and details for each event. *** ## Sample Projects Use the sample projects we've built to help you get started building quickly and learn from common development patterns. You can also find a list of community-maintained samples on [GitHub](https://github.com/discord/embedded-app-sdk-examples?tab=readme-ov-file#community-curated-examples), which includes more framework-specific examples. This TypeScript starter template is perfect for getting your own Activity up and running quickly. This reference example implements the commands and events available to you within the Embedded App SDK. This reference example demonstrates an Activity using a nested framework like a game engine. # Discord Bots & Companion Apps Source: https://docs.discord.com/developers/bots/overview Start building bots and companion apps for Discord. Discord Bots & Companion Apps Hero Image Bots are applications that connect to Discord using the Discord API. They appear in servers as users with an `APP` tag and can interact with members, respond to events, and perform actions programmatically. For a deeper look at what bots can do and when to use one, see the [Bots & Companion Apps](/developers/platform/bots) platform page. ## Getting Started To build a bot, you'll need to: * **Create an application** in the Discord Developer Portal. This is where your bot token, OAuth2 credentials, and configuration live. * **Add a bot user** to your application from the Bot tab. This generates the token your code uses to authenticate. * **Invite the bot** to a server using an OAuth2 URL with the bot scope and the permissions your bot requires. * **Connect to the API** using the Gateway for real-time events, the HTTP API for REST operations, or both. Most developers use a community-maintained library in their language of choice rather than interfacing with the API directly. Official and community libraries are listed in the [Community Resources](/developers/developer-tools/community-resources) page. If you're ready to dive in, the [Getting Started guide](/developers/quick-start/getting-started) walks through building and running your first bot end to end. ## Building Your Bot * **[Interactions](/developers/interactions/overview)** — Slash commands, context menu commands, buttons, select menus, and modals that let users interact with your bot. * **[Components](/developers/components/overview)** — Layout, content, and interactive UI elements you can attach to messages and modals. * **[Monetization](/developers/monetization/overview)** — Add subscriptions and one-time purchases to your bot using Discord's built-in payment flow. * **[Discovery](/developers/discovery/overview)** — Get your app listed in the App Directory and App Launcher so users can find and install it. * **[Guides & Tutorials](/developers/guides/bots)** — Practical guides on implementing common bot features and best practices. }> Step-by-step guide to building and running your first Discord bot. }> Explore guides on implementing common bot features and best practices. # Change Log Source: https://docs.discord.com/developers/change-log Discover the latest updates, new features, and bug fixes on the Discord Developer Platform. To join in on the conversation, join the [Discord Developers Server](https://discord.com/invite/discord-developers). ## Deprecation: Riot Games Connections in `Get Current User Connections` The new Riot Games connection is powered by the [Discord Social SDK](/developers/discord-social-sdk/overview) and application identities. As a result, newly created Riot Games connections are no longer returned by the [`Get Current User Connections`](/developers/resources/user#get-current-user-connections) endpoint (`GET /users/@me/connections`). Starting July 10, 2026, legacy Riot Games and League of Legends connections will also no longer be returned by this endpoint. There is no replacement for this functionality. ## Discord Social SDK Release 1.9.17379 A new release of the Discord Social SDK is now available, with the following updates: ### Stability * Fixed a crash caused by re-entrant HTTP requests during connection teardown on PlayStation 5. ## Discord Social SDK Release 1.9.17228 A new release of the Discord Social SDK is now available, with the following updates: ### Authentication * Fixed an issue where `AUTHORIZE_REQUEST` events would not re-subscribe after Discord disconnected and reconnected while the SDK was already running. ### Noise Suppression * Krisp noise suppression binaries and model files are now included in Unity and Unreal plugin packages for Windows, macOS, Android, and iOS. ## Attachment Editing and `is_spoiler` Param Apps can now edit the `description` and `is_spoiler` parameters on existing attachments when editing messages. We have also separated the [attachment request](/developers/resources/message#attachment-object-attachment-request-structure) object in the docs to make it more clear which params you can set for attachments and which fields are provided by the API. Attachments can be marked as a spoiler by setting `is_spoiler: true` in the attachment request object, and apps can read whether an existing attachment is spoilered by checking for the `IS_SPOILER` [attachment flag](/developers/resources/message#attachment-object-attachment-flags) on the attachment object. The legacy `SPOILER_` filename prefix will continue to mark attachments as a spoiler, but not all spoilered attachments have the prefix. ## Documentation Fix: Subscription Status Values The integer values for the `INACTIVE` and `ENDING` subscription statuses were previously swapped in the documentation. The correct values are `INACTIVE` = `1` and `ENDING` = `2`, as shown in the [Subscription Statuses](/developers/resources/subscription#subscription-statuses) reference. This has been corrected in both the reference and the [Implementing App Subscriptions](/developers/monetization/implementing-app-subscriptions) guide, which described the subscription lifecycle with the swapped values. The API has always returned these values, only the documentation was incorrect. If your app branches on the numeric `status` value, double-check that `1` is treated as `INACTIVE` and `2` as `ENDING`. We discovered this issue while reconciling our documentation against [our OpenAPI spec](https://github.com/discord/discord-api-spec) in [this commit](https://github.com/discord/discord-api-spec/commit/cdbd53a2ac5144536bfee2a34e6d0de13e08eec0). ## Changes to Privileged Intent Access for Discord Apps Privileged Intents Requirements Today, we're [announcing changes to how Discord Apps access Privileged Intent](https://support-dev.discord.com/hc/articles/40281523410967) with a new user-based threshold for when access requires review and an annual process to reapply for continued access. > If your app is accessible to fewer than 10,000 users, these changes do not impact your app. ### What's Changing #### 1. The review threshold is now based on user count, not server count Previously, apps in fewer than 100 servers could access Privileged Intents by toggling them on in the Developer Portal, and apps in 100+ servers needed to apply for access. Starting today, the threshold is based on the number of users your app can access across all the servers it belongs to. If your app has fewer than 10,000 users, you can continue accessing Privileged Intents by toggling them on in the Developer Portal. **Once your app reaches 10,000 users, you'll need to apply for Privileged Intent access**. #### 2. Apps must now reapply annually for continued access Apps with Privileged Intent access granted from a prior review will need to reapply to confirm their continued access once per year in the Developer Portal. #### 3. Apps can keep growing during Privileged Intent review Under the new user-based threshold, apps can continue joining servers and reaching new users while their submission is under review. #### 4. App Verification and Privileged Intent review are now separate Previously, [App Verification](https://support-dev.discord.com/hc/en-us/articles/23926564536471-How-Do-I-Get-My-App-Verified) and Privileged Intent review were part of the same review process. With this change, we have separated App Verification and the Privileged Intent review process. Privileged Intents Requirements ### What This Means For Your App For more information on how this applies to your Discord Apps, please read the [Privileged Intents Change announcement article](https://support-dev.discord.com/hc/articles/40281523410967) in our developer help center. ### Updated Documentation & Resources * Updated [Privileged Intents documentation](/developers/events/gateway#privileged-intents) to reflect the new threshold and review process. * New [Getting Started with Privileged Intents Review](/developers/gateway/getting-started-with-privileged-intent-review) guide. * New [You Might Not Need a Privileged Intent](/developers/gateway/you-might-not-need-a-privileged-intent) guide to help you determine whether you need a privileged intent or whether an alternative approach will work for your use case. ## Discord Social SDK Release 1.9.16441 A new release of the Discord Social SDK is now available, with the following updates: ### Playstation 5 * Fixed crash caused by use-after-free in WebSocket callbacks ## New Lobby HTTP API Endpoints We've expanded the Discord [Lobby resource](/developers/resources/lobby) reference with several public endpoints: * **[Create or Join Lobby](/developers/resources/lobby#create-or-join-lobby)** (`PUT /lobbies`) — create a lobby for your application or join an existing one by `secret` in a single call. * **[Send Lobby Message](/developers/resources/lobby#send-lobby-message)** (`POST /lobbies/{lobby.id}/messages`) — send a message into a lobby on behalf of an authenticated member. * **[Get Lobby Messages](/developers/resources/lobby#get-lobby-messages)** (`GET /lobbies/{lobby.id}/messages`) — fetch up to 200 of the most recent messages from a lobby the calling user is a member of. * **[Create Lobby Channel Invite for Self](/developers/resources/lobby#create-lobby-channel-invite-for-self)** and **[for User](/developers/resources/lobby#create-lobby-channel-invite-for-user)** — generate a single-use, one-hour guild invite to a lobby's linked channel. ## Discord Social SDK Release Cadence & Support We've published a new [Release Cadence & Support](/developers/discord-social-sdk/core-concepts/release-cadence-and-support) page for the Discord Social SDK. It documents: * Our new three-per-year minor release cadence (April, July, November) * A new support window covering the five most recent minor versions, with hotfix patches (bug fixes and security fixes) for older supported minor releases * How new Xbox and PlayStation OS SDK supports ship in new Social SDK releases only — each release bundles roughly the last 18 months of console OS SDKs * The new end-of-life process for older minor releases ### What this means for you * **Over a year and a half of support per minor release.** Three minor releases of the Social SDK per year combined with a 5-version support window means every minor release you ship with gets more than 18 months of patch coverage. * **A predictable release calendar.** Releases land in April, July, and November, so you can plan Social SDK upgrades and console certification windows well in advance. * **More bandwidth for new features and stability.** A defined support window lets us focus engineering effort where it matters most, which means more capacity to build new features in current minor releases and keep the versions in the support window robust and reliable. ### What changes with 1.10 These changes take effect with the 1.10 release, shipping in **July 2026**: * The supported version window will cover versions **1.6 through 1.10**. Versions **1.5 and earlier** will be end-of-life and no longer eligible for patch updates. * **New Xbox and PlayStation OS SDK support will ship in new Social SDK releases only**, not as patches to older Social SDK versions. Each Social SDK release will bundle roughly the last 18 months of console OS SDK versions. **Already-shipped Social SDK releases (1.6–1.9) are unchanged** — they keep the console OS SDK support they were originally built with. The new model applies from 1.10 forward. We're sharing this ahead of the 1.10 release so developers on older versions have plenty of time to upgrade. ## Account Linking Failure Modes We've expanded documentation across the Social SDK guides to cover what happens when the Discord-to-game account link is severed — whether by a Discord account ban, an explicit unmerge, or an OAuth2 token revocation. Highlights: * **[Ban-Driven Unmerge](/developers/discord-social-sdk/development-guides/using-provisional-accounts#ban-driven-unmerge)** documents the full lifecycle when a user's Discord account is banned: tokens are deleted immediately, a new cross-platform-restricted provisional account is created carrying the original external identity, and merge attempts return error [`530017`](/developers/discord-social-sdk/development-guides/using-provisional-accounts#merge-request-failures) until the ban lifts (or, for permanent bans, indefinitely). * **[Out-of-Band Revocation](/developers/discord-social-sdk/development-guides/account-linking-with-discord#out-of-band-revocation)** describes the auth-side observable signals (`APPLICATION_DEAUTHORIZED` webhook + `invalid_grant` on refresh) when a user removes your app from Discord or has their account banned. * **[When Refresh Fails](/developers/discord-social-sdk/development-guides/account-linking-with-discord#when-refresh-fails)** documents the `/oauth2/token` response when the underlying token has been deleted, and recommends treating `invalid_grant` as equivalent to receiving the webhook. ## Discord Social SDK Release 1.9.15780 A new release of the Discord Social SDK is now available, with the following updates: ### Xbox * Added Xbox GDK 260400 support ### Noise Suppression * Integrated Krisp noise suppression across Android, iOS, macOS, and Windows ## New `flags_new` Field on Application Object The [Application object](/developers/resources/application#application-object) now includes a `flags_new` field — a string-serialized integer containing the full set of [application flag bits](/developers/resources/application#application-object-application-flags), including any new flag bits introduced beyond bit 30. The existing `flags` field continues to be serialized as a 32-bit integer. Existing integrations consuming `flags` for bits at or below `2^30` are not impacted, and request payloads that include flag values should continue to use the original `flags` field. This mirrors the [`permissions_new` / `allow_new` / `deny_new`](/developers/topics/permissions) pattern previously introduced for permission bitfields. ## User Premium Type Field Now Requires A Scope The `premium_type` field on the [User object](/developers/resources/user#user-object-user-structure) will return `0` for applications that have not been approved for the `identify.premium` scope. To receive Nitro subscription level, you must request the `identify.premium` scope during OAuth authorization. Without this scope, the field returns `0` regardless of the user's actual subscription status. The `identify.premium` scope is only available to approved partners. ## Voice Muting Based on Player Blocks We've published a new how-to guide covering how to implement bi-directional voice muting in lobby voice calls based on block relationships. The guide covers two approaches for populating per-member mute lists — client-side using any client-accessible block signal (Discord relationships, in-game block lists, etc.) and server-side via lobby member metadata set at lobby creation — and a shared client-side implementation that applies mutes in both directions. As part of this work, we've also documented the [`POST /lobbies/{lobby.id}/members/bulk`](/developers/resources/lobby#bulk-update-lobby-members) endpoint, which allows adding, updating, or removing up to 25 lobby members in a single request. [Voice Muting Based on Player Blocks](/developers/discord-social-sdk/how-to/voice-muting-for-blocked-players) ## Discord Social SDK Release 1.9.15332 A new release of the Discord Social SDK is now available, with the following updates: ### Playstation 5 * Added OS 13.000 support ### Activity Invites * Accepting an activity invite over RPC now uses the `application_id` from the invite when provided, fixing cases where invites from sibling applications were sometimes attributed to the wrong app. This only affects teams leveraging Publisher Level Account Linking for having a single auth flow across all the games in their portfolio. ## Proximity Voice Chat Guide for Game Developers We've published a new guide on adding proximity voice chat to a multiplayer game using the Discord Social SDK and Unity. The guide walks through the general architecture and the concepts are adaptable to any game or engine. [Add proximity voice chat to your game](/developers/game-development/how-to-add-proximity-voice-chat-to-your-game) ## Security Updates for Provisional Account OIDC Integrations We've made security improvements to how Discord validates OIDC issuer URLs and fetches OIDC configuration for [provisional accounts](/developers/discord-social-sdk/development-guides/using-provisional-accounts) — including stricter hostname checks and blocking HTTP redirects during configuration and JWKS discovery. **Existing provisional account OIDC integrations are not affected** and will continue to work without any changes on your part. However, if you need to edit your OIDC configuration in the [Developer Portal](https://discord.com/developers/applications/select/social-sdk/external-auth-providers), your updated configuration will be validated against these requirements. We've published new documentation covering the full set of [OIDC Integration Requirements](/developers/discord-social-sdk/development-guides/using-provisional-accounts#oidc-integration-requirements) — including issuer URL rules, discovery document requirements, supported signing algorithms, and ID token claims. Before making any changes to a production integration, review those requirements and verify your configuration works in a test application first. ## Voice Channel Status and Start Time Documentation Voice channel status has been available for some time, but we're now officially documenting the endpoint, permission, and related Gateway and audit log events so apps can integrate with it. The [Set Voice Channel Status](/developers/resources/channel#set-voice-channel-status) endpoint (`PUT /channels/{channel.id}/voice-status`) allows apps to set a short string (up to 500 characters) describing what's happening in a voice channel. ### Permission Setting a channel's status requires the `SET_VOICE_CHANNEL_STATUS` permission (`1 << 48`), now documented in the [permissions](/developers/topics/permissions) table. If the bot user is not connected to the voice channel, the `MANAGE_CHANNELS` permission is additionally required. ### Gateway Events Voice channel status and voice session start time are ephemeral and are not included on the [channel](/developers/resources/channel#channel-object) object. To read them, apps send the [Request Channel Info](/developers/events/gateway-events#request-channel-info) Gateway command (opcode `43`) and receive a [Channel Info](/developers/events/gateway-events#channel-info) event containing the requested fields (currently `status` and `voice_start_time`) for channels in the guild. Two receive events are dispatched when these fields change: * [Voice Channel Status Update](/developers/events/gateway-events#voice-channel-status-update) — fired when a channel's status changes. * [Voice Channel Start Time Update](/developers/events/gateway-events#voice-channel-start-time-update) — fired when a voice session's start time changes. ### Audit Log Two [audit log events](/developers/resources/audit-log#audit-log-events) track status changes: `VOICE_CHANNEL_STATUS_UPDATE` (`192`) and `VOICE_CHANNEL_STATUS_DELETE` (`193`). A `status` field in [Optional Audit Entry Info](/developers/resources/audit-log#audit-log-entry-object-optional-audit-entry-info) carries the new status on `VOICE_CHANNEL_STATUS_UPDATE` entries. ## Deprecation: OAuth2 Refresh Token Grant for OIDC Provisional Accounts If you are using [OIDC server-side authentication](/developers/discord-social-sdk/development-guides/using-provisional-accounts#server-authentication-with-external-credentials-exchange) for provisional accounts, a `refresh_token` is returned — but using it via the OAuth2 `refresh_token` grant is now deprecated. This brings OIDC in line with all other provisional account authentication methods: when the token expires, re-authenticate using a fresh provider token and pass the new access token to [`Client::UpdateToken`]. See the [Refreshing Provisional Account Tokens](/developers/discord-social-sdk/development-guides/using-provisional-accounts#refreshing-provisional-account-tokens) section for details. [`Client::UpdateToken`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a606b32cef7796f7fb91c2497bc31afc4 ## Message Forwarding Requires Message Content Access Starting today, applications must be able to read a message's content in order to forward it. An application attempting to forward a message it cannot read will now receive error code `160014` with the message "You cannot forward a message whose content you cannot read." Most applications will not be affected by this change, but those recently affected have been notified directly via system DM. ## Discord Social SDK Release 1.8.14985 A new release of the Discord Social SDK is now available, with the following updates: ### Xbox * Added Xbox GDK 251002 support ## RPC over IPC Documentation Documentation for Discord's RPC over IPC (Inter-Process Communication) transport is now available. IPC is a transport for native applications to communicate with a local Discord client, offering high-performance local communication without network overhead. The [RPC documentation](/developers/topics/rpc) covers: * IPC socket paths for Windows and Linux/macOS * Handshake flow and opcodes * IPC-specific events (`READY`, `ERROR`, and `GUILD_STATUS`) If you're building a game that integrates Discord social features, we recommend using the [Discord Social SDK](/developers/discord-social-sdk/overview) instead of communicating directly over RPC. ## Discord Social SDK Release 1.8.14856 A new release of the Discord Social SDK is now available, with the following updates: ### iOS Unity & Unreal * Unity and Unreal packages now include Debug plugins, which have support for logging at the Info and Verbose severity levels ### Party Privacy * Fixed bug in which changes to party privacy settings didn't propagate when calling [`Client::UpdateRichPresence`], meaning switching a party from private to public wouldn't update the join button in Discord ## Search Guild Messages We've added documentation for the [Search Guild Messages](/developers/resources/message#search-guild-messages) endpoint, which allows bots to search for messages within a guild using a variety of filters. The endpoint supports filtering by content, author, channel, mentions, attachments, embeds, and more. Results can be sorted by timestamp or relevance. This endpoint requires the `READ_MESSAGE_HISTORY` permission and the `MESSAGE_CONTENT` [Privileged Intent](/developers/events/gateway#privileged-intents). The error code `110000` has been added to the [error codes](/developers/topics/opcodes-and-status-codes#json) table to reflect the index-not-ready response returned when a guild has not yet been indexed for search. ## Discord Social SDK Release 1.8.14587 A new release of the Discord Social SDK is now available, with the following updates: ### Debug Support * Added Debug library support for the following: * Unity plugin & sample * Unreal plugin & sample * Windows, Mac, Linux libraries * Android library * PS5 11.000 & 12.000 library * PS4 12.000 & 12.500 library * Scarlett & Xbox One 250400 GDK library ## Developer Portal & Docs Refresh The Developer Portal and Developer Docs have both been updated with improved navigation, usability, and a redesigned theme, with more developer experience improvements on the way. Latest changes include: ### Developer Portal * **New [dev portal home page](https://discord.com/developers/home)** with quick access to apps, docs, and new developer videos. * **New theme** with updated navigation and updated light/dark support. * **New Localization support!** This will use the same language you have set in the Discord client. ### Developer Docs * **Reorganized structure** with new tabs for each feature area and new sidebars for easier navigation. * **New guides and overviews** for platform-wide features and use cases, with more on the way! * **AI & MCP support:** Docs now work with AI development tools via Copy-as-Markdown, an LLMs.txt file, and an MCP server, available at `https://docs.discord.com/mcp` * **Existing docs URLs** are stable and were preserved during the reorganization. Some titles and content were updated or moved for clarity. ### What's Next We are working on more improvements for the portal and docs. We invite you to share any issues or feedback in the [Next Gen Docs discussion thread](https://github.com/discord/discord-api-docs/discussions/categories/next-gen-docs-feedback). ## Discord Social SDK Release 1.8.14437 A new release of the Discord Social SDK is now available, with the following updates: ### Security * Filter the bearer token in all levels of logging * Release builds only emit log statements for Error or Warning levels of severity * Debug builds will still have logs for Info and Verbose levels of severity * Added a DEBUG BUILD Warning at the top of the debug log that indicates it should not be used in production ## Discord Social SDK Release 1.7.14433 A new release of the Discord Social SDK is now available, with the following updates: ### Security * Filter the bearer token in all levels of logging * Release builds only emit log statements for Error or Warning levels of severity * Debug builds will still have logs for Info and Verbose levels of severity * Added a DEBUG BUILD Warning at the top of the debug log that indicates it should not be used in production ## Discord Social SDK Release 1.6.14448 A new release of the Discord Social SDK is now available, with the following updates: ### Security * Filter the bearer token in all levels of logging * Release builds only emit log statements for Error or Warning levels of severity * Debug builds will still have logs for Info and Verbose levels of severity * Added a DEBUG BUILD Warning at the top of the debug log that indicates it should not be used in production ## Updates to Context Menu Commands We've redone the UI for [User Commands](/developers/interactions/application-commands#user-commands) and [Message Commands](/developers/interactions/application-commands#message-commands) to make it easier to find commands and unlock higher limits! #### Refreshed UI The UI has been updated based on feedback! No longer do you have to scroll through a long list of commands: * Commands are now organized by their application, providing hierarchy * Frequently used commands are now hoisted to the top for easy access * A new search bar lets you quickly find the exact command you're looking for #### A Higher Limit We've heard your feedback about the 5 command limit feeling too restrictive! With this new UI, we have increased the limit to 15 per type, providing breathing room for your app. #### Developer Resources Check out the [Application Commands](/developers/interactions/application-commands) page for details on all command types. ## Server-Side Message Moderation We've released and documented two new API endpoints that enable you to modify the application-scoped moderation metadata on both game direct messages and lobby messages. Combined with the [previously announced](/developers/change-log#discord-social-sdk-release-1813395) [`MessageHandle::ModerationMetadata`], and game direct message and lobby [Webhook Events](/developers/events/webhook-events#event-types), this enables server-side lobby and game direct message moderation workflows. Your game backend can now evaluate messages and attach moderation metadata that the Discord Social SDK can then deliver to game clients in real time, driving in-game message rendering dependent on moderation results. To see this in detail, have a look at the newly updated [How To Integrate Moderation](/developers/discord-social-sdk/how-to/integrate-moderation) guide with the full server-side moderation flow. ## Discord Social SDK Release 1.8.14026 A new release of the Discord Social SDK is now available, with the following updates: ### Stabilization * Fixed an occasional crash when linking your Discord account to your Application while in a Voice Call ## Publisher Level Account Linking We've published new documentation for **Publisher Level Account Linking**, a feature that enables game publishers with multiple titles to implement a single authorization flow across their entire game portfolio. Publisher Level Account Linking requires Discord approval. To inquire about access, speak to your Discord account representative or [contact us](https://discord.com/developers/contact-us) With Publisher Level Account Linking, players authenticate once through a publisher application instead of separately for each game. This creates a simplified experience for players while giving publishers centralized account management capabilities. Key features covered in the guide: * Setting up parent-child application hierarchies between publisher and game applications * Exchanging parent access tokens for child access tokens * Integrating child tokens with the Discord Social SDK * Understanding token lifecycles and revocation To learn more and get started, check out the [Publisher Level Account Linking guide](/developers/discord-social-sdk/development-guides/publisher-level-account-linking). ## Discord Social SDK Release 1.8.13870 A new release of the Discord Social SDK is now available, with the following updates: ### Playstation 5 * Added OS 12.000 support ### iOS * Added code stripping to iOS builds to reduce size ## Community Invite Guide We're launching a guide to showcase the new [invite endpoints](/developers/change-log#new-invite-endpoints) and functionality. It has examples on how to create invites with roles through the UI and API and how to restrict access to an invite using `target_users` through the API. This guide highlights use cases for community servers and walks through steps for creating and sending invites that grant roles or restrict access to specific users. [Check out the new guide here!](/developers/tutorials/using-community-invites) ## Radio Groups, Checkbox Groups, and Checkboxes in Modals We're introducing three new modal components: **Radio Groups**, **Checkbox Groups**, and **Checkboxes**. These components expand the ways users can interact with your app through modals, enabling single-choice selections, multi-select options, and simple yes/no toggles. #### The New Components * [**Radio Group**](/developers/components/reference#radio-group): A single-selection component for choosing exactly one option from a list. Supports the `required` field to allow optional selections. * [**Checkbox Group**](/developers/components/reference#checkbox-group): A multi-selection component with configurable `min_values` and `max_values` constraints for flexible selection requirements. * [**Checkbox**](/developers/components/reference#checkbox): A simple boolean toggle for yes/no style questions. All three components must be placed inside a [**Label**](/developers/components/reference#label) component and are only available in modals. #### Developer Resources * [Using Modal Components](/developers/components/using-modal-components) - Learn how to create modals * [Component Reference](/developers/components/reference) - Complete documentation for all available components ## Next Generation Docs Project We're excited to announce the launch of our Next Gen Docs project! This initiative aims to improve the way developers interact with Discord's developer documentation, making it more accessible, comprehensive, and user-friendly. ## Our Goal The Discord API has evolved far beyond its origins as a platform for bots. Today, we're a comprehensive developer platform supporting: * **Discord Apps and Bots** - The foundation of our ecosystem, extending Discord's functionality with custom apps, commands, and integrations * **Discord Activities** - Real-time games and social experiences that users can launch directly inside Discord * **Social SDK for Games** - Bringing Discord-powered features like voice, chat, rich presence, and social graph to games Our documentation needs to evolve with us. With this project, we're not just updating our docs. We're aiming to improve the entire developer experience for learning and building on Discord as it exists in 2026 and beyond. ## Our Next Gen Docs Journey **What we've done so far:** * Migrated to [Mintlify](https://mintlify.com) for a modern documentation experience * For this migration, we preserved our existing content and familiar design but plan to evolve this over time * We no longer have to maintain and build our own documentation platform and can instead focus on making content and improving our developer experience * Gained new capabilities: * **PR Previews** - See documentation changes before they go live! This works locally as well as in your pull requests * **More Components and Docs Features** - We now have access to all of Mintlify's documentation components that will continue to grow over time * **AI features & improved search** - You can now send our docs to your LLM of choice or access them via MCP (more on this soon!) If you're reading this, the migration is complete! 🎉 This migration did require us to reorganize the entire repository and make a lot of formatting changes. If you have an open PR, it will be a pretty gnarly merge conflict to resolve. We will be focusing on getting our PR backlog down over the next few weeks. We combed through the existing documentation to ensure everything was migrated correctly, but if you spot anything that looks off, please let us know by opening an issue or submitting feedback [here](https://github.com/discord/discord-api-docs/discussions/categories/next-gen-docs-feedback). We will be actively monitoring feedback to quickly address any issues. ## Why This Matters Great documentation isn't just about having the right information, it's about presenting it in a way that helps developers succeed. In the coming months, we'll be shipping changes to our documentation to ensure that it: * **Reduces time-to-first-success** for new developers * **Scales with complexity** as your projects grow * **Stays current** with our rapidly evolving platform * **Serves all skill levels** from beginners to experts ## Contributing to Our Vision This transformation is happening with the developer community at its heart. We welcome: * **Feedback** on what's working and what isn't * **Content contributions** through our existing PR process * **Bug reports** when documentation doesn't match reality We have created a Github Discussion topic for [Next Gen Docs Feedback](https://github.com/discord/discord-api-docs/discussions/categories/next-gen-docs-feedback) to collect feedback. See our [Contributing Guidelines](https://github.com/discord/discord-api-docs/blob/main/CONTRIBUTING.md) for how to get involved. ## Community Invites Update We've updated the community invite endpoints with two changes due to a security concern: * [Get Target Users](/developers/resources/invite#get-target-users) returns a standardized CSV file with a header `user_id` and each user ID on its own line. If you relied on the header you submitted or weren't reading it from the file you got back you'll need to update to expect only `user_id` as the header in the csv now. * [Get Channel Invites](/developers/resources/channel#get-channel-invites) returns a partial for [roles](/developers/topics/permissions#role-object) instead of the full role object. This is a breaking change as it used to return the full role object and now only contains `id`, `name`, `position`, `color`, `colors`, `icon`, and `unicode_emoji`. ## Relationships.read scope We've opened up the `relationships.read` scope for Activities under the [Social SDK terms](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms). To get access to the scope you will need to accept the Social SDK terms for your app in the [Social SDK settings](https://discord.com/developers/applications/select/social-sdk/getting-started). Requesting approval for this scope from Discord is no longer necessary. With this scope `getRelationships()` in the embedded app SDK will now return a player's relationships. The Embedded App SDK is available via [npm](https://www.npmjs.com/package/@discord/embedded-app-sdk) and [GitHub](https://github.com/discord/embedded-app-sdk). You can check out our [installation guide and reference](/developers/developer-tools/embedded-app-sdk) to get started with it! ## New Invite Endpoints We've added new endpoints and functionality allowing invites to grant roles and to only be accepted by specified users. These are perfect for communities that want to manage access more granularly or reward members with special roles when they join a server. [Create Channel Invite](/developers/resources/channel#create-channel-invite) has been updated to support `target_users_file` and `role_ids` parameters. * `target_users_file`: A CSV file with user IDs to specify who can accept the invite * `role_ids`: Role IDs for roles to assign to users when they accept the invite Invite endpoints: * [Get Target Users](/developers/resources/invite#get-target-users): Gets the users allowed to see and accept an invite * [Update Target Users](/developers/resources/invite#update-target-users): Updates the users allowed to see and accept an invite * [Get Target Users Job Status](/developers/resources/invite#get-target-users-job-status): Checks the status of the job that processes the target users for an invite from file upload ## Discord Social SDK Release 1.8.13395 A new release of the Discord Social SDK is now available, with the following updates: ### Moderation Metadata Support * \[Coming Soon] Messages will soon support [`MessageHandle::ModerationMetadata`], a set of custom string key-value pairs that can be used to communicate moderation-related information between your game backend and client. * This SDK version includes the functionality to support this upcoming feature, but it will only become available after an upcoming Discord API change. ### WebSocket Reporting * WebSocket connection failures will now report an HTTP status code to the SDK log. ### PlayStation 5 * Improved accuracy of timing metrics used for monitoring the health of connections and voice calls. ## Discord Social SDK Release 1.7.13357 A new release of the Discord Social SDK is now available, with the following updates: * Fixed a crash on Steam Deck when calling RegisterLaunchCommand * Fixed a crash on iOS when Deeplink Authentication fails. ## New Social SDK Guide: Account Linking from Discord We've added a new guide showing how to enable account linking entry points within the Discord client. With Social SDK 1.6+, Discord can now display "Link your account" prompts and buttons throughout the client to encourage players to connect their game accounts, leading to higher linking rates and better social engagement. The guide covers two implementation flows: * **Connected Game Flow (recommended)**: Uses new callback methods to launch account linking directly in your game when players click Discord's entry points * **Web Flow**: Routes players through a web-based OAuth flow (currently only available for select partners) [Read the full guide →](/developers/discord-social-sdk/development-guides/account-linking-from-discord) ## Discord Social SDK Release 1.6.13305 A new release of the Discord Social SDK is now available, with the following updates: * Fixed a crash on Steam Deck when calling RegisterLaunchCommand * Fixed a crash on iOS when Deeplink Authentication fails. ## Get Guild Role Member Counts Endpoint Apps can now use the [Get Guild Role Member Counts](/developers/resources/guild#get-guild-role-member-counts) endpoint to access the number of members that have each role! ## Discord Social SDK Release 1.7.13152 A new release of the Discord Social SDK is now available, with the following updates: ### macOS * Added support for macOS 10.15 to the build. The minimum versions are now 10.15 for Intel Macs and 11.0 for Apple Silicon Macs. ## Permission Changes Going into Effect February 2026 for PIN\_MESSAGES, BYPASS\_SLOWMODE, CREATE\_GUILD\_EXPRESSIONS, and CREATE\_EVENTS We have some important permission changes that will take effect in February 2026. The introduction of the following permissions were non-breaking changes. However, the breaking changes described below - where the old permissions will no longer grant these abilities - will take effect on February 23, 2026. These changes involve a few permissions that we split from their original permission to provide more granular control over bot and user actions. ### What's Changing? **1. Pin Messages Permission** * The `PIN_MESSAGES` permission (`1 << 51`) was split from `MANAGE_MESSAGES` on August 20, 2025. * [Read the change log](/developers/change-log#pin-permission-split). * Starting February 23, 2026, users and bots will need the `PIN_MESSAGES` permission to pin messages. `MANAGE_MESSAGES` alone will no longer be sufficient. **2. Bypass Slowmode Permission** * The `BYPASS_SLOWMODE` permission (`1 << 52`) is being split from `MANAGE_MESSAGES`, `MANAGE_CHANNEL`, and `MANAGE_THREADS`. * [Read the change log](/developers/change-log#new-bypassslowmode-permission-permission-split). * Note: This primarily affects users, as bots are not affected by slowmode restrictions. * Starting on February 23, 2026, users will need the `BYPASS_SLOWMODE` permission to not be affected by slowmode restrictions. **3. Create Expressions Permission** * The `CREATE_GUILD_EXPRESSIONS` permission (`1 << 43`) was created in July 2023 and split from `MANAGE_GUILD_EXPRESSIONS` for users in December 2023. [Read the change log](/developers/change-log#clarification-on-permission-splits-for-expressions-and-events). * As of today, bots now have access to the `CREATE_GUILD_EXPRESSIONS` permission. * [Read the change log](/developers/change-log#guild-expressions-and-events-permissions-now-available-to-developers). * Starting on February 23, 2026, bots will need the `CREATE_GUILD_EXPRESSIONS` permission to create custom emoji and stickers. `MANAGE_GUILD_EXPRESSIONS` alone will no longer be sufficient. **4. Create Events Permission** * The `CREATE_EVENTS` permission (`1 << 44`) was created in July 2023 and split from `MANAGE_EVENTS` for users in December 2023. [Read the change log](/developers/change-log#clarification-on-permission-splits-for-expressions-and-events). * As of today, bots now have access to the `CREATE_EVENTS` permission. * [Read the change log](/developers/change-log#guild-expressions-and-events-permissions-now-available-to-developers). * Starting on February 23, 2026, bots will need the `CREATE_EVENTS` permission to create scheduled events. `MANAGE_EVENTS` alone will no longer be sufficient. ### What Do You Need to Do? If your bot performs any of the following actions, please review and update your bot's permission requests before February 23, 2026: * **Pins messages:** Request the `Pin Messages` permission * **Creates custom emoji or stickers:** Request the `Create Expressions` permission * **Creates scheduled events:** Request the `Create Events` permission These changes are designed to give server administrators more control over what bots and users can do, ensuring better security and permission management. ## New BYPASS\_SLOWMODE Permission & Permission Split We have introduced a new permission: `BYPASS_SLOWMODE`. This permission allows designated roles or users to bypass slowmode restrictions in channels. * The `BYPASS_SLOWMODE` permission (`1 << 52`) is being split from `MANAGE_MESSAGES`, `MANAGE_CHANNEL`, and `MANAGE_THREADS`. * Note: This primarily affects users, as bots are not affected by slowmode restrictions. * Starting on February 23, 2026, users will need the `BYPASS_SLOWMODE` permission to not be affected by slowmode restrictions. ## Guild Expressions and Events Permissions now available to developers In 2023, we had introduced permission splits for guild expressions (custom emoji and stickers) and scheduled events. These changes were made to give server administrators more granular control over who can create content in their communities. [Read the change log](/developers/change-log#clarification-on-permission-splits-for-expressions-and-events). Today, we are announcing that these permissions are now available for bot developers to use and will be required for certain actions starting **February 23, 2026**. **Create Guild Expressions Permission** * The `CREATE_GUILD_EXPRESSIONS` permission (`1 << 43`) was created in July 2023 and split from `MANAGE_GUILD_EXPRESSIONS` for users in December 2023. * As of today, bots now have access to the `CREATE_GUILD_EXPRESSIONS` permission. * Starting on February 23, 2026, bots will need the `CREATE_GUILD_EXPRESSIONS` permission to create custom emoji and stickers. `MANAGE_GUILD_EXPRESSIONS` alone will no longer be sufficient. **Create Events Permission** * The `CREATE_EVENTS` permission (`1 << 44`) was created in July 2023 and split from `MANAGE_EVENTS` for users in December 2023. * As of today, bots now have access to the `CREATE_EVENTS` permission. * Starting on February 23, 2026, bots will need the `CREATE_EVENTS` permission to create scheduled events. `MANAGE_EVENTS` alone will no longer be sufficient. ## Discord Social SDK Release 1.7.13024 A new release of the Discord Social SDK is now available, with the following updates: ## Windows * Fixed default audio device selection to once again prefer the default system audio device instead of the default communications device. ## Xbox * Added support for GDK 240605 to the build. ## Discord Social SDK Release 1.7 A new release of the Discord Social SDK is now available, with the following updates: ## Authentication * Sign in with Apple and PlayStation Network are now supported as external identity providers. ## Linked Channels * The results of [`Client::GetGuildChannels`] are now sorted in the order in which they appear in the Discord client. Additional properties added to [`GuildChannel`] for type, position and parent category ID. ## PlayStation 5 * Added Low Energy Mode support. Explicit control of SDK thread affinity is provided by `cpuAffinityMask` property of [`ClientCreateOptions`]. * Fixed a crash when destroying and recreating [`Client`]. ## Windows * Fixed an issue which caused local crash dumps to be disabled in processes which load the Social SDK. ## Voice * The Social SDK now uses our latest audio subsystem on Windows, bringing it more in line with the desktop client. Improves device compatibility and fixes some long-standing issues like Bluetooth devices changing profiles on startup. * Desktop clients now use WebRTC m130 internally (upgraded from m116). * Bug fixes and improvements to DAVE E2EE protocol implementation. ## Discord Social SDK Release 1.6.12767 A new release of the Discord Social SDK is now available, with the following update: Implemented a fix for a crash on Playstation when creating the Discord client, destroying it, and creating another. ## Discord Social SDK Release 1.5.12211 A new release of the Discord Social SDK is now available, with the following update: ## Bug Fix * Fixed a crash when calling [`Client::GetUserGuilds`] on iOS devices. First occurrence of this crash introduced in 1.5.10839 ## Discord Social SDK Release 1.6.12170 A new release of the Discord Social SDK is now available, with the following updates: ## New Features This small update to v1.6 adds some highly requested features from our partners. We found some time to sneak them in… * You can now provide custom art to display as a banner image in game invites that appear in Discord. This is done one of two ways: * By specifying a URL or an `asset key` to an image in the `activity.assets.inviteCoverImage` parameter when calling `Client::UpdateRichPresence`. This method even affords you the ability to set a unique image on each invite if you want! * By uploading cover image art in the `Rich Presence` tab in the Developer Portal for your Application. Note: This will be used as the fallback image if you don't specify one via `activity.assets.inviteCoverImage` * It's now possible to customize the displayed name for your Application in Discord's Rich Presence. To do so, set the `activity.name` parameter when calling [`Client::UpdateRichPresence`] * Added support for Microsoft Xbox GDK version 2025.04 * Fixed a crash when calling [`Client::GetUserGuilds`] on iOS devices ## Introducing the File Upload component in Modals Have you ever wanted to collect more than text from a user through a modal? With the new [**File Upload**](/developers/components/reference#file-upload) component you can! You can specify a min and max number of files accepted between 0 and 10, and if uploading files within that limit is required before submitting. Any file types are accepted, and the max file size is based on the user's upload limit in that channel. #### The New Component: * [**File Upload**](/developers/components/reference#file-upload) #### Developer Resources * [Using Modal Components](/developers/components/using-modal-components) - Dive into creating a modal * Check out our [Component Reference](/developers/components/reference) for details on all available components. ## Discord Social SDK Release 1.6 A new release of the Discord Social SDK is now available, with the following updates: ### ✨ New Features * When calling [`Client::GetGuildChannels`], channels are now sorted by their `position` field, which matches how they are sorted in the Discord client. * Messages received via the Social SDK, no longer create notifications in a Discord client for the same user, to avoid double notification on the same machine. **This release adds features to support upcoming Discord experiments that will enhance how games integrate with user profiles and authentication:** * **Game Profile Integration**: New functionality to display game data on Discord user profiles. This includes `UserApplicationProfile` support with two new methods: `Client::GetUserApplicationProfiles` and `Client::GetUserApplicationProfilesNoLock` on the Users class, which retrieve game identity data from external authentication providers. * **In-Discord Authentication Flow**: Support for users to start account linking directly from Discord (rather than having to initiate it from within your game). Added [`Client::RegisterAuthorizeRequestCallback`] and [`Client::RemoveAuthorizeRequestCallback`] methods to handle authentication requests that originate from various Discord entry points. These functions support upcoming Discord client experiments that will be gradually rolled out to users over time. ### ⚠️ Deprecations This deprecation aims to improve consistence across the SDK's API surface as well as provide a safer implementation that has fewer edge cases and less potential for accidental misuse. * Deprecated [`Client::GetCurrentUser`] API in favor of [`Client::GetCurrentUserV2`] which returns optional values instead of potentially invalid handles. ### 🚀 Performance Improvements * This update implements caching capabilities for the [`Client::GetUserMessagesWithLimit`] function to avoid unnecessary remote API calls when sufficient messages are already cached locally. ### 🎤 Voice Communications Fixes and Improvements Fixes several critical bugs with the voice communications system, as well as improved overall reliability, and noise and echo suppression and cancellation. * Fixed an issue where voice calls would sometimes transition to `Disconnected` state instead of reconnecting properly after a network interruption. * Extended AGC2 (Automatic Gain Control 2) support to mobile platforms ### 🐛 General Stability and Bug Fixes Multiple general critical bugs that can cause crashes and panics. We highly recommend upgrading to 1.6 to avoid them in your game. * Fixed critical bug where activity party privacy wasn't properly set, causing "ask to join" to appear instead of "join" for public parties. * Fixed critical memory safety issue preventing connection objects from being deallocated during timer callbacks. * Fixed C# marshaling alignment bugs and double-free crashes. * Improved gateway resilience with fallback to generic URLs on zonal gateway failures. * Fixed WebSocket write-after-close errors preventing connection issues. To learn more about building with the Discord Social SDK, check out the [Discord Social SDK Overview](https://discord.com/developers/docs/discord-social-sdk/overview), and if you have questions, feel free to drop them in [#social-sdk-dev-help](https://discord.com/channels/613425648685547541/1350223314307776592)! ## Adding More Modal Components! We've added more components to modals! All select menus (User, Role, Mentionable, Channel) are now fully supported in modals. In order to use a select menu in a modal, it must be placed inside a [Label](/developers/components/reference#label) component. We've also added the [Text Display](/developers/components/reference#text-display) component with markdown support as a top-level component in modals. #### Components Now Supported in Modals: * [**User Select**](/developers/components/reference#user-select) * [**Role Select**](/developers/components/reference#role-select) * [**Mentionable Select**](/developers/components/reference#mentionable-select) * [**Channel Select**](/developers/components/reference#channel-select) * [**Text Display**](/developers/components/reference#text-display) #### Getting Started * [Using Modal Components](/developers/components/using-modal-components) - Dive into creating a modal #### Developer Resources Check out our [Component Reference](/developers/components/reference) for details on all available components. ## Banner, avatar, and bio can be set on modify current member As of September 10, 2025, bots can set `banner`, `avatar`, and `bio` fields using the [modify current member](/developers/resources/guild#modify-current-member) route. ## Deprecating Non-E2EE Voice Calls We started work on end-to-end encryption for Discord over two years ago to enhance our user privacy and security. With DAVE now supported across all platforms, we’re very close to making every call fully end-to-end encrypted. ### Developer Impact To support our long-term privacy goals, we will **only support E2EE calls starting on March 1st, 2026** for all audio and video conversations in direct messages (DMs), group messages (GDMs), voice channels, and Go Live streams on Discord. After that date, any client or application not updated for DAVE support will no longer be able to participate in Discord calls. ### Implementing E2EE Voice For developers working with Discord's voice APIs, you can consult [the updated voice documentation](/developers/topics/voice-connections) and the implementation examples available in our [open-source repository](https://github.com/discord/libdave) as well as [the protocol whitepaper](https://github.com/discord/dave-protocol). The [Discord Developers community](https://discord.gg/discord-developers) is also a great place to find assistance and answers to any integration questions you may have. We're committed to making this transition as smooth as possible while delivering the enhanced privacy and security that DAVE provides to all Discord users. ## Discord Social SDK Release 1.5.11353 A new release of the Discord Social SDK is now available, with the following updates: ### Unity Plugin * Fixed a crash primarily affecting low-end Android devices (those with armv7 architecture) in [`Client::CreateOrJoinLobbyWithMetadata`] * Fixed a crash when passing large amounts of metadata in [`Client::CreateOrJoinLobbyWithMetadata`] The Discord Social SDK binaries are available for download in the Developer Portal after enabling the Discord Social SDK for your application. To learn more about building with the Discord Social SDK, check out the [Discord Social SDK Overview](/developers/discord-social-sdk/overview). [`Client::CreateOrJoinLobbyWithMetadata`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a5c84fa76c73cf3c0bfd68794ca5595c1 ## Introducing New Modal Components! You asked for them, and now they're here! Modals are getting new components!! #### What's New We're introducing a new top-level [Label](/developers/components/reference#label) component for modals that have a `label`, `description`, and can contain a Text Input or a String Select! You heard right, String Selects now work in modals! * String Selects now work in modals when placed inside a Label component * Text Inputs can also be used inside a Label component * When a Text Input is used in a Label component the `label` field on the Text Input is not allowed in favor of `label` on the Label component * ActionRow + TextInput is now deprecated in favor of the new Label component for better accessibility * The `required` field is now available on String Selects (defaults to true in modals, ignored in messages) * The `disabled` field on String Selects is not currently allowed in modals, and will trigger an error if used We've also documented [modal interaction responses](/developers/interactions/receiving-and-responding#interaction-object-component-interaction-response-structures) and resolved objects for interactive components in each component's Examples section. #### New Layout Component * [**Label**](/developers/components/reference#label) - A new top-level component that lets you add a title and description to your modal components! #### Updates to Modal Components * [**Text Input**](/developers/components/reference#text-input) - Text Input can now be used in a [Label](/developers/components/reference#label) * [**String Select**](/developers/components/reference#string-select) - String Selects can be used in modals! Place them in a [Label](/developers/components/reference#label) #### Getting Started * [Using Modal Components](/developers/components/using-modal-components) - Dive into creating a modal #### Developer Resources Check out our [Component Reference](/developers/components/reference) for details on all available components. ## Pin Permission Split [Pinning](/developers/resources/message#pin-message) and [unpinning](/developers/resources/message#unpin-message) messages now has its own [permission](/developers/topics/permissions#permissions-bitwise-permission-flags). We split `PIN_MESSAGES` out of `MANAGE_MESSAGES` to give more granular control over who can pin messages in a channel. This is effective immediately for both users and apps. This change will be backwards compatible until January 12th 2026 when `MANAGE_MESSAGES` will no longer grant the ability to pin or unpin messages. ## Discord Social SDK Release 1.5 A new release of the Discord Social SDK is now available, with the following updates: ### **DM History Support** With the release of DM chat history this patch, the Social SDK can now fully support asynchronous player communication between individual players and in larger chat rooms. Players who go offline or background the game can come back to the history of the chat room and get caught up with what’s happening. * Added [`Client::GetUserMessageSummaries`] and [`Client::GetUserMessagesWithLimit`] to retrieve direct message history ### Rich Presence Rich Presence can now more accurately display the different types of activities a player might be engaged in. Specifically, the “Competing” status may be valuable for games that host tournaments, weekend brackets, or other competitive play. Also, when you receive game invites, you can now accept them cross-device; don’t miss the group forming even if you’re AFK. * Added support for additional activity types (Listening, Watching, Competing) * Added support for new clickable URL fields and additional user status customization * Support for server-to-server rich presence invites and gateway-based invite handling. This means an invite can be accepted on a different device and the [`Client::SetActivityInviteCreatedCallback`] will be invoked on connected SDK sessions. ### Linked Channels Linked channels are all about keeping groups of friends connected in and outside the game. You can now join a player to channel’s linked Discord server from in-game, helping them bridge that gap and stay connected with friends even when they stop playing. * Added [`Client::JoinLinkedLobbyGuild`] to allow members of linked lobbies to join the linked lobby's guild from in-game ### Android The many-step process of mobile account linking has been simplified for users with Discord installed by deep-linking into the Discord mobile app to authorize with your game * Implemented native authentication support * Fixed native authentication callback when activities are terminated * Added an experimental audio setting on Android to avoid setting the OS to voice comms mode when connected to a Bluetooth headset on Android. This may be used if you wish to avoid the transition to voice volume controls and other related changes when connected to Bluetooth. To enable this setting, pass a [`ClientCreateOptions`] when instantiating the client and set the `experimentalAndroidPreventCommsForBluetooth` flag Video showing off the account linking process in 1.4 vs 1.5 on Android ### iOS The many-step process of mobile account linking has been simplified for users with Discord installed by deep-linking into the Discord mobile app to authorize with your game * Added native authentication support * The experimental Game audio subsystem now makes use of the iOS 18.2+ echo canceller when available and falls back to Standard mode otherwise. ### Windows * Added ARM64 support ### Linux * Ensured glibc 2.31 compatibility ### Bug Fixes * Fixed bug where [`Client::SetVoiceLogDir`] didn’t have any effect * Added better error event handling to distinguish server authorization errors from user cancellations * Fixed activity platform validation for console games * Fixed crash safety issues with [`Client::GetCurrentUser`] when the client is in an unexpected non-Ready state. Added [`Client::GetCurrentUserV2`] which explicitly returns an optional handle instead of dummy data in this situation. This issue also affected the Unity and Unreal versions of the SDK * Fixed [`Call::SetPTTActive`] ## Known Issues * When the network is disconnected temporarily, active Calls may sometimes enter the Disconnected state instead of reconnecting. If a Call reaches Disconnected state, you must end and rejoin the call to reconnect if desired. * For DM chat history * No SDK-side caching for [`Client::GetUserMessagesWithLimit`] * Every invocation of [`Client::GetUserMessagesWithLimit`] will directly query the backend rather than using local SDK-side caching. This may have performance implications, particularly under high-frequency usage. * Provisional account merge message retrieval * After a provisional account is merged into a full account, messages sent while the user was on the provisional account cannot be retrieved. ## Introducing Rate Limit When Requesting All Guild Members We're introducing a change to the [Request Guild Members](/developers/events/gateway-events#request-guild-members) gateway opcode. ### What's changing? We are implementing a rate limit on the [Request Guild Members](/developers/events/gateway-events#request-guild-members) opcode[.](https://takeb1nzyto.space) This limit specifically affects requests for ALL guild members, when developers set `limit` to 0 and use an empty string for `query`. Note: This rate limit applies only to the initial request when requesting ALL Guild Members, not to the Guild Members Chunk events that are sent in response. * **Rate Limit:** 1 request per guild per bot every 30 seconds * **Scope:** The limit applies per guild per bot (one bot can request members for different guilds within the 30-second window) * **Behavior:** Requests that exceed this limit will receive a [`RATE_LIMITED`](/developers/events/gateway-events#rate-limited) event as a response: ```js theme={"system"} { "op": 0 "t": "RATE_LIMITED", "d": { "opcode": 8, "retry_after": ..., "meta": { "guild_id": ..., "nonce": ... } } } ``` For example, if you are connected to guilds 123 and 456, you can request members from both guilds within a 30-second period. However, you cannot make a second request to guild 123 within that same 30-second window. ### Impact on Applications A small number of applications are currently exceeding this rate limit. If your app heavily relies on this opcode, we recommend reviewing your current implementation and making necessary adjustments to maintain functionality. ### Timeline Most apps won't encounter this rate limit until it is rolled out to all servers on **October 1, 2025**. However, if you are the developer of an app that is requesting all guild members in very large guilds then you may start seeing this **as soon as today**, so we can ensure platform stability. ### What you need to do If your application uses [Request Guild Members](/developers/events/gateway-events#request-guild-members) to request all members, we recommend: * Implement caching mechanisms for member data * Update your cache using the `GUILD_MEMBER_ADD`, `GUILD_MEMBER_UPDATE`, and `GUILD_MEMBER_REMOVE` gateway events If you hit this limit, you will receive the [`RATE_LIMITED`](/developers/events/gateway-events#rate-limited) event as a response. ## Discord Social SDK Communication Features - General Availability Communication features (cross-platform messaging, voice chat, lobbies, and linked channels) are now generally available for all Discord Social SDK users that meet our application process criteria. Previously available only in closed beta, these features enable seamless player interaction within your game. * **Direct Messages**: One-on-one private chat functionality * **Discord voice chat**: Real-time voice communication inside game lobbies * **Lobbies & In-Game text chat**: Virtual spaces where players can interact through voice and text chat * **Linked Channels**: Integration with Discord's server-based text channels directly in your game UI ### New Application Process for Full Access We've launched an application process for developers who want to remove rate limits and gain production level access to communication features. Developers can now apply through our developer portal with detailed game information and usage projections to unlock production-level capacity. As part of documenting this application process, we have also documented pre-approval rate limits, so you can build, test and develop against the Social SDK with confidence. ### Get Started with the Social SDK The Discord Social SDK binaries are available for download in the Developer Portal after enabling the Discord Social SDK for your application. To learn more about building with the Discord Social SDK, check out the [Discord Social SDK Overview](/developers/discord-social-sdk/overview). ## Embedded App SDK Version 2.1 & 2.2 We've made a few improvements to the Embedded App SDK for version 2.2.0, here are the highlights: ### Changes in version 2.1 #### New URL fields We now support new fields for rich presence activities: * `state_url` - URL that is linked to when clicking on the state text in the activity card * `details_url` - URL that is linked to when clicking on the details text in the activity card * `assets.large_url` - URL that is linked to when clicking on the large image in the activity card * `assets.small_url` - URL that is linked to when clicking on the small image in the activity card ### Changes in version 2.2 #### patchUrlMappings In line with the [recent change](/developers/change-log#remove-proxy-from-discord-activity-proxy-path) to remove the `.proxy/` path from Discord Activity proxy URLs, the `patchUrlMappings` utility has been updated to generate simplified URLs by default. It will now create mappings without the `.proxy/` prefix. The Embedded App SDK is available via [npm](https://www.npmjs.com/package/@discord/embedded-app-sdk) and [GitHub](https://github.com/discord/embedded-app-sdk). You can check out our [installation guide and reference](/developers/developer-tools/embedded-app-sdk) to get started with it! ## Remove .proxy/ from Discord Activity proxy path We've updated the Content Security Policy (CSP) for Discord Activities to remove the `.proxy/` path requirement when making requests through the discordsays.com proxy. This change simplifies the developer experience while maintaining full backwards compatibility. This was made possible by resolving the underlying privacy considerations that originally required the `.proxy/` path restriction. #### Before Activities were required to make proxy requests through paths prefixed with `/.proxy/`: ``` https://.discordsays.com/.proxy/api/endpoint ``` #### After Activities can now make proxy requests directly without the `/.proxy/` prefix: ``` https://.discordsays.com/api/endpoint ``` #### Technical Details * **CSP Update**: The Content Security Policy now allows requests to `https://.discordsays.com/*` instead of the more restrictive `https://.discordsays.com/.proxy/*` * **Proxy Behavior**: Both URL patterns work identically - your existing proxy mappings (e.g., `/api -> example.com`) will function the same way regardless of whether you use `/.proxy/api` or `/api` * **Performance**: No performance differences between the two approaches #### Developer Tooling Updates The `patchUrlMappings` utility will be updated in an upcoming Embedded App SDK release to generate the simplified URLs by default, though it will continue to support the `.proxy/` format for backward compatibility. #### Backward Compatibility **All existing code will continue to work without changes.** The `/.proxy/` path prefix is still fully supported and will be maintained indefinitely. You can: * Continue using existing `/.proxy/` URLs * Switch to the new, simplified URLs * Use both patterns simultaneously in the same application **No migration is required.** This is a purely additive change that expands what's possible rather than breaking existing functionality. ## Guild Create Deprecation Apps can no longer create guilds. The documentation for these endpoints has been removed and the endpoints have been removed from the OpenAPI specification. See our [earlier changelog entry](/developers/change-log#deprecating-guild-creation-by-apps) for more information. ## Clickable Links and Customizable Statuses in Rich Presence We've added new functionality to Rich Presences to give users of your application a more interactive and flexible experience. There are two big changes as part of this: * You can now add clickable links to the state text, details text, large image & small image * You can now choose which field (name, state, or details) is used in users' status text in the member list (e.g. instead of "Listening to MyMusic" you can now have your status text show "Listening to Rick Astley") All of these new fields are documented on the [Activity Object](/developers/events/gateway-events#activity-object) section of Gateway Events and also available through the Embedded App SDK. ## Gradient Roles and Guild Tags We've documented gradient role colors and guild tags in the API. Guild tags let users rep their favorite server with a 1-4 character badge next to their display name. They can be accessed using the `primary_guild` field on the user object. Servers can now give gradient colors to their roles instead of a single, solid color. Gradient colors use the new `colors` field on the role object. As part of this change, the `color` field on roles is now deprecated, but it will still work for backwards compatibility. #### Gradient Role Colors * The guild feature `ENHANCED_ROLE_COLORS` will let you know if a guild is able to set gradient colors to roles. * Guild roles now have `colors` as part of the [structure](/developers/topics/permissions#role-object-role-structure). * `color` on guild roles is deprecated but will still be returned by the API and continues to work for backwards compatibility. * [Role color structure](/developers/topics/permissions#role-object-role-colors-object) #### Guild Tags * Guild tags can be retrieved through the `primary_guild` field on the user object. * [User Primary Guild](/developers/resources/user#user-object-user-primary-guild) ## Discord Social SDK Release 1.4 A new release of the Discord Social SDK is now available, with the following updates: ### Lobby Chat History * Added [`Client::GetLobbyMessagesWithLimit`] to retrieve lobby message histories based on a provided lobby ID, with a maximum of 200 messages and up to 72 hours. * Only messages from lobbies the user is currently a member of can be retrieved. * DM history will be coming soon too! ### Unified Friends List * Added [`Client::GetRelationshipsByGroup`] which both logically groups a user’s relationships for the purpose of rendering a friends list and sorts users based on our [Unified Friends List design guidelines](/developers/discord-social-sdk/design-guidelines/unified-friends-list). Before, it was necessary to call [`Client::GetRelationships`] and manually partition each relationship into the appropriate friend group, as well as write your own sorting operations. * Added [`Client::SetRelationshipGroupsUpdatedCallback`] which fires whenever a user change occurs which could invalidate a previously sorted friends list retrieved from [`Client::GetRelationshipsByGroup`]. Call [`Client::GetRelationshipsByGroup`] again to maintain an up-to-date friends list. * Added `IsSpamRequest` to [`RelationshipHandle`], returns `true` if Discord believes the request to be spam. ### Audio Changes * A new experimental audio mode has been added for mobile devices which uses standard media audio streams instead of voice-specific processing. On iOS this causes the voice engine to use the Remote I/O Audio Unit instead of Voice Processing I/O and likewise on Android, media stream types are used instead of voice communication types. This mode may be enabled by creating a Client with a [`ClientCreateOptions`] parameter whose `experimentalAudioSystem` property is set to `AudioSystem::Game`. In this case, you should also set [`Client::SetEngineManagedAudioSession`] to true. **We do not recommend using this for production** - however, if you are interested in trying it out, we are looking for feedback! * Added [`Client::SetAecDump`] to enable recording of audio diagnostic information. ### Auth * Publisher Auth * Publisher Auth is a new feature which makes authorization easier for publishers with multiple games. This is an early release of this feature and only available to a limited number of partners for now. * Added [`Client::ExchangeChildToken`] to facilitate child token exchange for public clients. Confidential clients will require a server to server implementation, but this method may be useful for development. * Invites from sibling applications will be visible to the SDK. They can be identified by the `applicationId` field on the [`ActivityInvite`] payload. * Messages sent from other sibling applications will be visible to the SDK. They can be identified by the `ApplicationId` method on the [`MessageHandle`]. * Added [`Client::RevokeToken`] and [`Client::UnmergeIntoProvisionalAccount`] to allow games leveraging Public Clients to perform token revocation or unmerge operations directly from clients. ### Android * The SDK is now compatible with 16KB page size. ### Misc * Improved activity serialization, avoiding including null/empty keys in the JSON payload. ## Paginated Pin Endpoints We've added new endpoints to manage paginated pins in channels. The Get Channel Pins endpoint allows you to retrieve and manage pinned messages in a more efficient way, especially for channels with a large number of pinned messages. Both Pin and Unpin endpoints remain the same with a new route. As part of this change we have deprecated the old endpoints for pinned messages. Switching to the new endpoints should be straightforward, as they maintain similar functionality but with improved pagination support. #### New Endpoints **[Get Channel Pins](/developers/resources/message#get-channel-pins)**: Retrieve a list of pinned messages in a channel with pagination support: /channels/[\{channel.id}](/developers/resources/channel#channel-object)/messages/pins **[Pin Message](/developers/resources/message#pin-message)**: Pin a message in a channel: /channels/[\{channel.id}](/developers/resources/channel#channel-object)/messages/pins/[\{message.id}](/developers/resources/message#message-object) **[Unpin Message](/developers/resources/message#unpin-message)**: Unpin a message in a channel: /channels/[\{channel.id}](/developers/resources/channel#channel-object)/messages/pins/[\{message.id}](/developers/resources/message#message-object) #### Deprecated Endpoints **[Get Pinned Messages](/developers/resources/message#get-pinned-messages-deprecated)**: /channels/[\{channel.id}](/developers/resources/channel#channel-object)/pins **[Pin Message](/developers/resources/message#pin-message-deprecated)**: /channels/[\{channel.id}](/developers/resources/channel#channel-object)/pins/[\{message.id}](/developers/resources/message#message-object) **[Unpin Message](/developers/resources/message#unpin-message-deprecated)**: /channels/[\{channel.id}](/developers/resources/channel#channel-object)/pins/[\{message.id}](/developers/resources/message#message-object) ## Discord Social SDK Release 1.3 A new release of the Discord Social SDK is now available, with the following updates: ### Authentication * Added an `APPLICATION_DEAUTHORIZED` webhook event which can be configured in the developer portal. When a user unlinks their account or revokes authorization for your application in any way, this event will be sent to configured webhooks. The payload will contain serialized user information. See [Webhook Events](/developers/events/webhook-events) docs for more information on configuring webhook events. ### PC * Added configurable request timeout SDK HTTP client requests. Support is on PC in this release with console and mobile support coming in future release. Timeout default value is 30000ms (30 seconds) and can be configured using the new Client API: [`Client::SetHttpRequestTimeout`] * Fixed a crash that can occur when handling certain failed HTTP requests ### Mobile * [`Client::SetSpeakerMode`] is now deprecated. Unless [`Client::SetEngineManagedAudioSession`] is used, audio routing will be handled automatically by the SDK #### Android * Fixed routing of game and voice audio when external audio devices are connected and/or disconnected. [`Client::SetEngineManagedAudioSession`] has been added to communicate that the SDK should not manage audio routing and automatically enter and leave `MODE_IN_COMMUNICATION` when joining and leaving calls. * Fixed an issue with the Authorize method when a device configuration change needs to restart the activity #### iOS * Various fixes for audio routing and session management. When using the Unity plugin, game audio will no longer stop playing when ending a call. For standalone SDK use, a method [`Client::SetEngineManagedAudioSession`] has been added to communicate that the SDK should not automatically start and stop the `AVAudioSession` when joining and leaving calls. * Corrected supported platform values in `Info.plist` for iOS .frameworks. ### Consoles * Standalone archives now only contain console-specific files, like the Unity and Unreal Engine archives ### Misc * Fixed a thread safety issue with [`Client::AddLogCallback`] * Added \[Flags] declaration for bit flags enums in C# ## Discord Social SDK Release 1.2 A new release of the Discord Social SDK is now available, with the following updates: ### Rich Presence * Added support for adding custom buttons on activity cards via [`Activity::AddButton`] ### Packaging * Unity and Unreal plugin artifacts now contain just the additional files for console support so they can be extracted on top of the base plugin * Unity plugin is now packaged as a .zip that you should extract inside the Packages directory of your project to enable the above * Console archives now contain a small README with some console-specific documentation ### Misc * Added [`Client::OpenConnectedGamesSettingsInDiscord`] for deeplinking into Discord's settings for connected games, which provides players some control over who can DM them * Fixed a hang that could occur on Linux in [`Client::RegisterLaunchCommand`] and [`Client::RegisterLaunchSteamApplication`] * [`Client::RegisterLaunchCommand`] and [`Client::RegisterLaunchSteamApplication`] now work from inside the Steam Runtime on Linux * Fixed a crash on exit that could occur when there were pending callbacks in the queue ## Raised Component Limits We're removing the top level component limit and raising the limit on number of components in a message to 40 when using the [`IS_COMPONENTS_V2` message flag](/developers/resources/message#message-object-message-flags)! We're also removing the limit on the number of components in a [Container Component](/developers/components/reference#container). Legacy messages have not changed and continue to allow up to 5 action rows. #### What's New * **Total components**: The limit for total components in a message has been increased to 40. * **Top-level components**: There is no longer a limit on top level components in a message (previously it was 10). * **[Container Component](/developers/components/reference#container)**: There is no longer a limit on the number of components in a Container Component (previously it was 10). #### Developer Resources * Check out our [Component Reference](/developers/components/reference) for detailed specifications on all available components. * Learn how to build rich message layouts with components with [Using Message Components](/developers/components/using-message-components). ## Introducing New Components for Messages! We're bringing new components to messages that you can use in your apps. They allow you to have full control over the layout of your messages. #### Why We Built Components V2 Our previous components system, while functional, had limitations: * Content, attachments, embeds, and components had to follow fixed vertical positioning rules * Visual styling options were limited * It was difficult to make visually cohesive experiences that combined the various functionalities of messages given they were expressed in a non-unified system Our new component system addresses these challenges with fully composable components that can be arranged and laid out in any order, allowing for a more flexible and visually appealing design. #### What's New [Components V2](/developers/components/overview) introduces several new component types that can be used in messages: #### New Layout Components * [**Section**](/developers/components/reference#section) - Combine text with an accessory component for contextually linked elements * [**Container**](/developers/components/reference#container) - Create visually distinct groupings with a customizable accent color * [**Separator**](/developers/components/reference#separator) - Add visual spacing and dividers between components #### New Content Components * [**Text Display**](/developers/components/reference#text-display) - Add rich markdown-formatted text anywhere in your messages * [**Thumbnail**](/developers/components/reference#thumbnail) - An image used in a [section](/developers/components/reference#section) * [**Media Gallery**](/developers/components/reference#media-gallery) - Present collections of images and videos in an organized grid * [**File**](/developers/components/reference#file) - Embed file attachments as part of your message layout #### Getting Started To use the new components, you'll need to send the message flag `1 << 15` (`IS_COMPONENTS_V2`) which activates the components system on a per-message basis. We've created guides to help you implement these new features: * [Using Message Components](/developers/components/using-message-components) - Learn how to build rich message layouts with components * [Using Modal Components](/developers/components/using-modal-components) - Create interactive forms and dialogs #### Compatibility Notes [Legacy component behavior](/developers/components/reference#legacy-message-component-behavior) will continue to work as before, so your existing integrations won't break. However, when using the Components V2 flag, you'll need to adapt to a few changes: * The `content` and `embeds` fields will no longer work but you'll be able to use [Text Display](/developers/components/reference#text-display) and [Container](/developers/components/reference#container) as replacements * Attachments need to be exposed through components to be visible. You can use a [Media Gallery](/developers/components/reference#media-gallery), [Thumbnail](/developers/components/reference#thumbnail), or [File](/developers/components/reference#file) component to display them * The `poll` and `stickers` fields are disabled * A max of 10 top-level components and 30 total components in a message #### Developer Resources Check out our [Component Reference](/developers/components/reference) for detailed specifications on all available components. We can't wait to see what you build! ## Discord Social SDK Release 1.1.8318 A new release of the Discord Social SDK is now available, with the following updates: ### Platforms * Playstation standalone archives now include linker stubs ### Voice * Fixed a regression in audio playback on Linux The Discord Social SDK binaries are available for download in the Developer Portal after enabling the Discord Social SDK for your application. To learn more about building with the Discord Social SDK, check out the [Discord Social SDK Overview](/developers/discord-social-sdk/overview). ## Discord Social SDK Release 1.1 A new release of the Discord Social SDK is now available, with the following updates: ### Platforms * Added Xbox One and PS4 console support ### Auth * Added support for Unity Services as an external auth provider ### Voice * [`Client::StartCallWithAudioCallbacks`] now permits sample data to be modified during record and playback for custom effects processing * Fixed a bug where the speaking state for a user could be stuck in the "on" state * Added [`Call::GetPTTReleaseDelay`] * Initialization of the voice engine is now delayed until it's needed * Fixed a deadlock with the Linux PulseAudio backend where malfunctioning audio devices could cause a voice engine lockup ### Rich Presence * Added support for sending rich presence updates and invites without connecting to the Discord gateway on desktop ### Misc * Added Linux support for [`Client::RegisterLaunchCommand`] and [`Client::RegisterLaunchSteamApplication`] * Fixed a crash when a Unity Editor scripting domain reload (e.g. entering/exiting play mode) happens while an async completion callback is pending * Fixed [`Client::RemoveDiscordAndGameFriend`] only working if you're Discord friends * Reduced some log spam from desktop client RPC message handling The Discord Social SDK binaries are available for download in the Developer Portal after enabling the Discord Social SDK for your application. To learn more about building with the Discord Social SDK, check out the [Discord Social SDK Overview](/developers/discord-social-sdk/overview). ## Deprecating Guild Creation by Apps ### Breaking Change To address security concerns, we are deprecating the ability for applications to create guilds using the `Create Guild` endpoint. #### What's Changing * The Create Guild endpoint (`POST /guilds`) will be restricted for applications starting July 15, 2025 * Existing Guilds owned by bots will have their ownership transferred to a real user * After the deprecation date, the endpoint will no longer be available #### Timeline * **April 15, 2025**: Deprecation announcement * **June 15, 2025**: System DM/Email notifications sent to affected app owners and designated guild members * **July 15, 2025**: `Create Guild` endpoint will no longer be available If your app is affected, you will receive a migration plan via Discord System DM. We understand this change may affect some legitimate use cases. If you have questions or believe your application requires continued access to guild creation functionality, please contact us through the [Developer Support portal](https://support-dev.discord.com/hc). ## Custom Incentivized Links ### Custom Incentivized Links for Activities Custom Incentivized Links are used to customize how your incentivized link embed appears to users. You can create them in the developer portal or generate them from within your activity. Incentivized Links can be used as referral links, promotions, deep-linking into your activity, and more. * shareLink will now let you attach custom params to links you share about your game using `custom_id`. * Removed `referrer_id` from shareLink API. Any uses of `referrer_id` should be moved over to use `custom_id` instead. Passing `referrer_id` to shareLink will silently fail. Learn more about [creating and managing Custom Incentivized Links](/developers/activities/development-guides/growth-and-referrals#creating-and-managing-custom-incentivized-links) and [how to generate them from within your activity](/developers/activities/development-guides/growth-and-referrals#generating-a-custom-link-within-your-activity) with the shareLink API. The Embedded App SDK is available via [npm](https://www.npmjs.com/package/@discord/embedded-app-sdk) and [GitHub](https://github.com/discord/embedded-app-sdk). You can check out our [installation guide and reference](/developers/developer-tools/embedded-app-sdk) to get started with it! ## Per-Attachment File Upload Behavior for Apps Starting today, file upload limits for apps are checked per-attachment rather than per-message. This change makes the app attachment behavior the same as when a user uploads multiple attachments on a single message. * File size limits now apply to each individual attachment * Previously, limits were applied to the combined size of all attachments in a message * This aligns app attachment handling with user attachment behavior The interaction payload will also include a new `attachment_size_limit` key that specifies the maximum allowed attachment size. This limit may be higher than the default attachment size limit, depending on the guild's boost status or the invoking user's Nitro status. For more information, check out [our documentation on file uploads](/developers/reference#uploading-files). ## Introducing the Discord Social SDK Developers can now use the Discord Social SDK to build social features into their games, enabling friends lists, cross-platform messaging, voice and more for all players — with or without a Discord account. Discord Social SDK offers features that enhance connectivity and player engagement, including: * Account Linking * Provisional Accounts * Rich Presence * Deeplink Game Invites Additionally, available in a closed beta to support in-game communications: * Cross-Platform Messaging * Linked Channels * Voice Chat Developers can request expanded access to these available features via the closed beta. #### Discord Social SDK Developer Resources New resources are available in the Developer Portal to help you get started with the Discord Social SDK: * [Getting Started Guides](/developers/discord-social-sdk/getting-started) for C++, Unity and Unreal Engine. * [Development Guides](/developers/discord-social-sdk/development-guides) for building your game's social features. * [Design Guidelines](/developers/discord-social-sdk/design-guidelines) for designing your game's social features. * [SDK Reference](http://discord.com/developers/docs/social-sdk/index.html) is now available. * The Discord Social SDK binaries are available for download in the Developer Portal after enabling the Discord Social SDK for your application. To learn more about building with the Discord Social SDK, check out the [Discord Social SDK Overview](/developers/discord-social-sdk/overview). ## Default File Upload Limit Change On January 16, 2025, the default file upload limit will change from 25 MiB to 10 MiB. While this limit is already active for users and bot users, it hasn't yet been applied to webhooks. * This change will take effect on January 16, 2025. * The 10 MiB limit will apply to both webhooks and interaction responses. For more information, check out [our documentation on file uploads](/developers/reference#uploading-files). ## Premium Apps: Multiple Subscription Tiers Developers with monetization enabled can now create and publish multiple subscription SKUs of the same type for their app. This allows developers to offer different subscription tiers with varying benefits and pricing. Users can upgrade and downgrade between published subscription SKUs. ### What's Changed #### Developer Portal * Under the `Monetization` tab, you can now publish multiple subscription SKUs of the same type for your app. #### App's Store Page * When multiple subscription SKUs are published: Users can now upgrade or downgrade between different published subscription SKUs. #### User App Subscription Settings * When multiple subscription SKUs are published: Users can now upgrade or downgrade between different published subscription SKUs. * These settings are available under `User Settings → Subscriptions → App Subscriptions`. #### Subscription Object * New field `renewal_sku_ids` added to the [subscription object](/developers/resources/subscription#subscription-object) response for `SUBSCRIPTION_UPDATE` events and API endpoints. * `renewal_sku_ids` is a list of snowflakes that indicate the SKU(s) that the user will be subscribed to at renewal. #### Updated Guide: Managing SKUs * The [Managing SKUs](/developers/monetization/managing-skus#creating-a-sku) guide has been updated to include information about creating and managing multiple subscription SKUs. #### Updated Guide: Implementing App Subscriptions * The [Implementing App Subscriptions](/developers/monetization/implementing-app-subscriptions#supporting-upgrades-and-downgrades) guide has been updated to include information about supporting upgrades and downgrades between multiple subscription SKUs. ## Entitlement Migration Completed The [entitlement migration](/developers/change-log#premium-apps-entitlement-migration-and-new-subscription-api) which began on **October 1, 2024**, has been successfully completed as of **November 1, 2024**. ### What's Changed * The documentation has been updated to reflect the new entitlement system as the standard behavior. * `ENTITLEMENT_UPDATE` event for subscription-related entitlements now only occur when the subscription ends. * The `ends_at` value on the [entitlement object](/developers/resources/entitlement#entitlement-object) is now set when the subscription ends. * To determine when a subscription was canceled, listen for `SUBSCRIPTION_UPDATE` events or use the [Subscription API](/developers/resources/subscription) to retrieve the subscription's `status` and `canceled_at` timestamp. For more details about the migration process, please refer to the [migration guide](/developers/change-log#updates-to-entitlement-migration-guide). ## Webhook Events You can now subscribe to a limited number of HTTP-based outgoing [webhook events](/developers/events/webhook-events#event-types) after [configuring a webhook events URL](/developers/events/webhook-events#configuring-a-webhook-events-url). Currently, 3 events are available: `APPLICATION_AUTHORIZED`, `ENTITLEMENT_CREATE`, and `QUEST_USER_ENROLLMENT`. Read the [webhook events](/developers/events/webhook-events) documentation for details on subscribing and using webhook events. When developing [user-installable apps](/developers/resources/application#user-context), [Application Authorized](/developers/events/webhook-events#application-authorized) (which is not available via [the Gateway](/developers/events/gateway)) is useful to receive events when your app was installed to a user or server. `ENTITLEMENT_CREATE` is the only monetization-related event available using webhook events, so you should still use the Gateway for [entitlement-related events](/developers/events/gateway-events#entitlements). Other monetization-related events will be supported via webhook events soon. ## Updates to Entitlement Migration Guide The entitlement migration started on **October 1, 2024** and will continue through 11:59PM PST on **November 1, 2024**. We updated our previous entitlement migration guide to provide more up-to-date information on impacts of developer impacts. Here's a summary of the changes we made: * The migration will run through November 1, 2024 to ensure that any entitlements that are set to renew in October will be properly migrated to the new entitlement system upon renewal. * `ENTITLEMENT_UPDATE` events will only occur when a subscription ends. * The value of the `ends_at` in `ENTITLEMENT_UPDATE` events indicate the timestamp for **when the entitlement is no longer valid**. * The `ends_at` value on the [entitlement object](/developers/resources/entitlement#entitlement-object) is set when the subscription ends. * To receive the value of when a subscription was canceled, you should listen for the `SUBSCRIPTION_UPDATE` events or use the [Subscription API](/developers/resources/subscription). View the [updated migration guide](/developers/change-log#premium-apps-entitlement-migration-and-new-subscription-api). To see a full diff of the changes, refer to this pull request: [Entitlement Migration Guide Updates](https://github.com/discord/discord-api-docs/pull/7201). ## Activities General Availability Following up on [the rollout of the App Launcher](https://discord.com/blog/discover-more-ways-to-play-with-apps-now-anywhere-on-discord), we’re excited to announce that [Activities](/developers/activities/overview) are now generally available for developers. In addition to API stability, this means that apps with Activities can now be [verified](https://support-dev.discord.com/hc/en-us/articles/23926564536471-How-Do-I-Get-My-App-Verified), [discoverable](/developers/discovery/enabling-discovery) in the App Directory, and [implement monetization](/developers/monetization/overview). ### Recent API Updates Since the developer preview was announced, there have been a few important API updates: * Activities can now enable and implement monetization features, and [`getEntitlements`](/developers/developer-tools/embedded-app-sdk#getentitlements),[`getSkus`](/developers/developer-tools/embedded-app-sdk#getskus), and [`startPurchase`](/developers/developer-tools/embedded-app-sdk#startpurchase) are generally available in the Embedded App SDK. * New [Get Application Activity Instance](/developers/resources/application#get-application-activity-instance) endpoint to make [managing Activity instances](/developers/activities/development-guides/multiplayer-experience#activity-instance-management) easier. * Apps with Activities can create an [Entry Point command (type `4`)](/developers/interactions/application-commands#entry-point-commands), which are the primary entry point for Activities in the App Launcher. When new apps enable Activities, a [default Entry Point command](/developers/interactions/application-commands#default-entry-point-command) will be created for the app. Read the [original change log](/developers/change-log#entry-point-commands) and the [Entry Point command guide](/developers/activities/development-guides/user-actions#setting-up-an-entry-point-command) for details. * Activities can now be launched in response to interactions using the `LAUNCH_ACTIVITY` (type `12`) [interaction callback type](/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type) for `APPLICATION_COMMAND`, `MESSAGE_COMPONENT`, and `MODAL_SUBMIT` [interaction types](/developers/interactions/receiving-and-responding#interaction-object-interaction-type). * Apps can now be installed to users (in addition to servers). After [setting up your installation contexts](/developers/resources/application#setting-supported-installation-contexts), make sure to request the `application.commands` scope when authorizing with users to make sure your Activity is available for them across their Discord servers, DMs, and Group DMs. * In August, there were updates to the Content Security Policy (CSP) for Activities that limits how you can make requests to external resources when building Activities. Read [the change log](/developers/change-log#activities-proxy-csp-update) and the guide on [using external resources](/developers/activities/development-guides/networking#using-external-resources) for details. ### Documentation Updates We’ve also added and improved the documentation for Activities and the Embedded App SDK to make it easier to build: * New reference documentation for [Monetization](/developers/monetization/overview) SDK commands: [`getEntitlements`](/developers/developer-tools/embedded-app-sdk#getentitlements),[`getSkus`](/developers/developer-tools/embedded-app-sdk#getskus), and [`startPurchase`](/developers/developer-tools/embedded-app-sdk#startpurchase) * Updated [Embedded App SDK Reference](/developers/developer-tools/embedded-app-sdk) documentation that adds signatures and arguments * Updated development guides for [Activity Instance Management](/developers/activities/development-guides/multiplayer-experience#activity-instance-management) and [Activity Proxy Considerations](/developers/activities/development-guides/networking#activity-proxy-considerations) when using external resources * New guide on implementing [In-App Purchases (IAP) for Activities](/developers/monetization/implementing-iap-for-activities) * New guides for [Verification and Discovery Surfaces](/developers/discovery/overview) * New guide on [Using Rich Presence with the Embedded App SDK](/developers/rich-presence/using-with-the-embedded-app-sdk) ## Soundboard API [Soundboard](/developers/resources/soundboard) is now available in the API! Apps can now [get](/developers/resources/soundboard#list-default-soundboard-sounds) soundboard sounds, [modify](/developers/resources/soundboard#modify-guild-soundboard-sound) them, [send](/developers/resources/soundboard#send-soundboard-sound) them in voice channels, and listen to other users playing them! ## Voice End-to-End Encryption (DAVE Protocol) Introduced [high-level documentation](/developers/topics/voice-connections) for Discord's Audio and Video End-to-End Encryption (DAVE) protocol, and the [new voice gateway opcodes](/developers/topics/opcodes-and-status-codes#voice) required to support it ### **Developer Impact** Starting September 2024, Discord is migrating voice and video in DMs, Group DMs, voice channels, and Go Live streams to use end-to-end encryption (E2EE). **Who this affects:** Any libraries or apps that support [Voice Connections](/developers/topics/voice-connections). You are not immediately required to support the E2EE protocol, as calls will automatically upgrade/downgrade to/from E2EE depending on the support of clients in the call. ### **Implementing E2EE Voice** We have added high-level documentation for Discord's Audio and Video End-to-End Encryption (DAVE) protocol, and the new voice gateway opcodes required to support it. The most thorough documentation on the DAVE protocol is found in the [Protocol Whitepaper](https://daveprotocol.com/). You can also use our open-source library [libdave](https://github.com/discord/libdave) to assist with your implementation. The exact format of the DAVE protocol opcodes is detailed in the [Voice Gateway Opcodes section of the protocol whitepaper](https://daveprotocol.com/#voice-gateway-opcodes). ### **Future Deprecation and Discontinuation of Non-E2EE Voice** Non-E2EE connections to voice in DMs, Group DMs, voice channels, and Go Live streams will eventually be deprecated and discontinued. In 2025, all official Discord clients will support the protocol and it will be an enforced requirement to connect to the end-to-end encryption-eligible audio/video session types listed above. Once a timeline for deprecation and discontinuation is finalized, we will share details and developers will have **at least six months** to implement before we sunset non-E2EE voice connections. Read more about Discord's Audio and Video End-to-End Encryption (DAVE) protocol: * [Meet DAVE: Discord's New End-to-End Encryption for Audio & Video](https://discord.com/blog/meet-dave-e2ee-for-audio-video) * [DAVE Protocol Whitepaper](https://daveprotocol.com/) * [libdave open-source library on GitHub](https://github.com/discord/libdave) ## Add Polls when Editing Deferred Interaction Responses You can now create a poll while editing a deferred interaction response with the [Edit Original Interaction Response](/developers/interactions/receiving-and-responding#edit-original-interaction-response) endpoint. Poll away! ## Premium Apps: Entitlement Migration and New Subscription API Updates to this Change Log entry was published on **October 7, 2024** to reflect up-to-date information. See the [new Change Log entry](/developers/change-log#updates-to-entitlement-migration-guide) for details on updates. We are migrating our entitlement system to a new behavior where entitlements will not end until explicitly canceled, representing a breaking change for subscription management. We are introducing a [Subscription API](/developers/resources/subscription) and [Subscription Events](/developers/events/gateway-events#subscriptions) to allow handling subscription-related events. This change will be rolled out to all existing applications that have entitlements for user and guild subscription SKUs, starting on October 1, 2024. #### Entitlement Migration Details * `ENTITLEMENT_CREATE` events will now be triggered with a null `ends_at` value for all ongoing subscriptions, indicating an indefinite entitlement. * `ENTITLEMENT_UPDATE` events will occur only when a subscription ends, with the `ends_at` value indicating the end date. * Discord-managed Subscription entitlements will have an `type` value of `PURCHASE` (type `1`) instead of `APPLICATION_SUBSCRIPTION` (type `8`). ### Migration Plan & Guide: As of **October 1, 2024**, all existing entitlements that grant access to user-subscription and guild-subscription SKUs will automatically transfer to the new system on their renewal date. This means we will have a month-long migration window to allow all of your entitlements to migrate to the new system upon renewal. Developers are advised to update their systems to handle the new `ENTITLEMENT_CREATE` and `ENTITLEMENT_UPDATE` events according to the following migration guide before the rollout date to avoid service disruptions. ### Introducing a New Subscription API With the new entitlement behavior, entitlements for subscription SKUs will no longer emit events at the start of a new subscription billing period. Instead, subscription lifecycle management can be handled through the new [Subscription API](/developers/monetization/implementing-app-subscriptions#using-the-subscription-api). Developers should refer to the [Subscription resource](/developers/resources/subscription) for information on calling the Subscription API and responding to Subscription events. For in-depth implementation details, see our [Implementing App Subscriptions](/developers/monetization/implementing-app-subscriptions#using-the-subscription-api) guide. You can start using this API now. ### Monetization Documentation Updates As part of these changes, we've updated the documentation for Premium Apps. * Created a new [Enabling Monetization](/developers/monetization/enabling-monetization) page to cover setting up your team, managing payouts, and enabling monetization for your apps * Created a new [Managing SKUs](/developers/monetization/managing-skus#creating-a-sku) page to document how to create, update, publish, and promote your SKUs * Moved and added [Entitlement](/developers/resources/entitlement), [SKU](/developers/resources/sku) and [Subscription](/developers/resources/subscription) resources to the **Resources** section * Updated guides for [Implementing App Subscriptions](/developers/monetization/implementing-app-subscriptions) and [Implementing One-Time Purchases](/developers/monetization/implementing-one-time-purchases) ### Subscription Entitlement Migration Guide Starting on **October 1, 2024**, we will be migrating our existing entitlement system to a new behavior where **entitlements do not expire until explicitly canceled**. This migration guide outlines the changes and impacts of this migration on developers and guides how to manage these changes effectively. With this update, entitlements for subscription SKUs will no longer emit events when a new subscription billing period begins. If you need to know when a subscription has been renewed, use the new [Subscription API](/developers/resources/subscription) and related [Subscription Gateway Events](/developers/events/gateway-events#subscriptions). ### Current System Currently, entitlements for Subscription SKUs purchased through Discord have: * An `ends_at` date that corresponds to the subscription interval. This date is updated at each billing cycle. * A entitlement `type` value of `APPLICATION_SUBSCRIPTION` (type `8`). * An `ENTITLEMENT_UPDATE` event is triggered at the start of each new subscription period. ### New System Post-migration, entitlements for Subscription SKUs purchased through Discord will: * No longer have an end date (`ends_at` will be `null`) until the user decides to cancel the subscription. * Now have an entitlement `type` value of `PURCHASE` (type `1`). * No `ENTITLEMENT_UPDATE` events will be triggered until the subscription is canceled. ### Migration Timeline * **Migration Start Date:** October 1, 2024 * **Migration End Date:** November 1, 2024 ### Migration Impacts ### 1) Existing Entitlements Scheduled to Renew * **During Migration Window:** * These will automatically transfer to the new system. * A new `ENTITLEMENT_CREATE` event will be triggered to indicate the migration. This does not indicate a net new entitlement. * No further events will be generated until the entitlement ends, which will then trigger an `ENTITLEMENT_UPDATE` event. * The `ends_at` value in the `ENTITLEMENT_UPDATE` event and in the Entitlement API will indicate the timestamp when the entitlement ends. ### 2) Existing Entitlements Set to End * **During Migration Window:** * These entitlements will naturally expire and not renew under the new system. * No new entitlement events will be generated for these cases. ### Developer Actions * **Pre-Migration:** * Review and understand the new entitlement event structure. * Adjust your system to handle `ends_at` being null, which now indicates an indefinite entitlement. * Adjust your system not to expect type `APPLICATION_SUBSCRIPTION` (type `8`) for Discord-managed subscription entitlements. * **Post-Migration:** * Monitor for `ENTITLEMENT_CREATE`, `ENTITLEMENT_UPDATE`, `SUBSCRIPTION_CREATE`, and `SUBSCRIPTION_UPDATE` events. * Update any references to an entitlement `ends_at` timestamps, which now indicate the ending of an entitlement. If you need to know when a subscription's period ends, use the [Subscription API](/developers/resources/subscription) and related [Subscription Gateway Events](/developers/events/gateway-events#subscriptions). ## Launching Activities in Response to Interactions [Activities](/developers/activities/overview) can now be launched as a response to interactions using the `LAUNCH_ACTIVITY` (type `12`) [interaction callback type](/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type). `LAUNCH_ACTIVITY` can be used in response to `APPLICATION_COMMAND`, `MESSAGE_COMPONENT`, and `MODAL_SUBMIT` [interaction types](/developers/interactions/receiving-and-responding#interaction-object-interaction-type). ## Entry Point Commands Apps with [Activities](/developers/activities/overview) enabled can now create [Entry Point commands](/developers/interactions/application-commands#entry-point-commands) using the `PRIMARY_ENTRY_POINT` (type `4`) [command type](/developers/interactions/application-commands#application-command-object-application-command-types). Apps are limited to one globally-scoped Entry Point command, which appears in the App Launcher. When creating or updating an Entry Point command, an [Entry Point handler](/developers/interactions/application-commands#application-command-object-entry-point-command-handler-types) can be defined using the [`handler` field](/developers/interactions/application-commands#application-command-object-application-command-structure). The `handler` field determines whether your app wants to manually handle responding to the interaction: * If the value is `DISCORD_LAUNCH_ACTIVITY` (`2`), Discord will automatically handle the interaction and send a follow-up message to the channel where the Entry Point command was invoked from. * If the value is `APP_HANDLER` (`1`), your app will receive an interaction token and will be responsible for responding to the interaction. In this case, you can launch your Activity using the `LAUNCH_ACTIVITY` (type `12`) [interaction callback](/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type). More details about Entry Point commands can be found in the [Application Commands documentation](/developers/interactions/application-commands#entry-point-commands) and in the [Activity development guide](/developers/activities/development-guides/user-actions#setting-up-an-entry-point-command). ### Default Entry Point Commands Starting today, when you enable Activities in your [app's settings](http://discord.com/developers/applications), a [default Entry Point command](/developers/interactions/application-commands#default-entry-point-command) called "Launch" will automatically be created for your app. This can be customized or deleted like other commands if you want to update the name or handler type. ## Voice Encryption Modes Added documentation for voice [encryption modes](/developers/topics/voice-connections#transport-encryption-modes) `aead_aes256_gcm_rtpsize` and `aead_xchacha20_poly1305_rtpsize` while announcing the deprecation of all `xsalsa20_poly1305*` variants and `aead_aes256_gcm`. Deprecated encryption modes will be discontinued as of November 18th, 2024. Deprecated encryption modes will be discontinued as of November 18th, 2024. ## Voice Gateway Version 8 and Deprecation of Versions \< 4 We are officially deprecating some very old voice gateway versions (> 7 years ago). * The voice gateway now supports a resume which re-sends lost messages. Use voice gateway version 8 and refer to [Buffered Resume](/developers/topics/voice-connections#buffered-resume). * We have removed the default option for voice gateway version. Once this is deprecated, you must pass a voice gateway version. You will be required to pass a voice gateway version and deprecated voice gateway versions will be discontinued as of November 18th, 2024. See [Voice Gateway Versioning](/developers/topics/voice-connections#voice-gateway-versioning) for further details. ## Get Guild Role Endpoint Need to get just one role, not the whole role list? Use the new [Get Guild Role](/developers/resources/guild#get-guild-role) endpoint to fetch a single role by ID. ## User App Install Count We've added an approximate user install count to the [Application object](/developers/resources/application#application-object) for user-installable apps. You can also view an app's install counts in the developer portal. ## Voice State Endpoints Voice states can now be accessed over the HTTP API! Apps can use the new [Get Current User Voice State](/developers/resources/voice#get-current-user-voice-state) and [Get User Voice State](/developers/resources/voice#get-user-voice-state) endpoints to fetch a user's voice state without a Gateway connection. ## Supported Activity Types for SET\_ACTIVITY The [`SET_ACTIVITY` RPC command](/developers/topics/rpc#setactivity) has been updated to support 3 additional [activity types](/developers/events/gateway-events#activity-object-activity-types): Listening (`2`), Watching (`3`), and Competing (`5`). Previously, it only accepted Playing (`0`). The [Game SDK](/developers/developer-tools/game-sdk#activities) has not been updated to support setting [`ActivityType`](/developers/developer-tools/game-sdk#activitytype-enum), and is still limited to read-only (to handle events that you receive from Discord). ## Application Emoji You can now upload emojis for your application in your [app's settings](https://discord.com/developers/applications) and use them as custom emojis anywhere on Discord. * Up to 2000 emojis per app * Support for user-installable apps * Can be [managed via the API](/developers/resources/emoji#create-application-emoji) with a bot token ## Activities Proxy CSP Update This change is outdated. We have since updated the Activities Proxy CSP and the use of `/.proxy/` is no longer required. For the latest information, please refer to [this changelog](/developers/change-log#remove-proxy-from-discord-activity-proxy-path). This change will be rolled out to all existing applications on **August 28, 2024**. We will be updating our Content Security Policy (CSP) for the Activities Domain (`https://.discordsays.com`). This represents a **breaking change** for **all Activities**, and as such we have a migration plan in order. our CSP will be updated as follows: * all requests must be made through `https://.discordsays.com/.proxy/`, and requests to other paths on the `discordsays.com` domain will be blocked. * requests to `https://discord.com/api/` will be permitted, but other paths on the `discord.com` domain will be blocked. * Only allowed paths on `cdn.discordapp.com` and `media.discordapp.net` will be permitted such as `/attachments/`, `/icons/`, and `/avatars/`. * nested child iframes must also mount paths prepended by `/.proxy/` As of [embedded-app-sdk v1.4.0](https://github.com/discord/embedded-app-sdk/releases/tag/v1.4.0) we have updated `patchUrlMappings` to automatically route requests through `/.proxy/`, so updating your SDK version calling `patchUrlMappings` is a good first step. If you are unfamiliar with `patchUrlMappings`, please consult the [documentation](/developers/activities/development-guides/networking#using-external-resources). All Application IDs created after `07/17/2024 12:00:00` UTC (applicationID greater than `1263102905548800000`) will also automatically have the new CSP applied. Testing your production code on a new application created after this date is a suggested way for developers to test compliance with this new CSP. ## Guild Member Banners Apps can now access guild member profile banners via the API and Gateway! The [guild member object](/developers/resources/guild#guild-member-object) now includes a `banner` field which can be used to create the [guild member banner URL](/developers/reference#image-formatting). ## Message Forwarding rollout We are slowly rolling out the message forwarding feature to users. This feature allows callers to create a message using `message_reference.type = FORWARD` and have the API generate a `message_snapshot` for the sent message. The feature has [some limitations](/developers/resources/message#message-reference-types) and the snapshot is a minimal version of a standard `MessageObject`, but does capture the core parts of a message. The resulting message will look something like: ```json theme={"system"} { "id": "1255957733279273083", "message_reference": { "type": 1, // Forward ... } "message_snapshots": [ { "message": { "content": "original message", "embeds": [...], "attachments": [...], ... } } ], ... } ``` We have applied stricter rate limits for this feature based on the following: * number of forwards sent by the user * total attachment size ###### API Updates since preview This was [previously announced](https://discord.com/channels/613425648685547541/697138785317814292/1233463756160503859) but note that the final API has a few changes since the API was first previewed: * [`message snapshot`](/developers/resources/message#message-snapshot-object) objects don't include a `guild` field anymore since the `message_reference` already provides that information * forwarded messages have a distinctive `message_reference` type of `FORWARD` now ## Banners in Get Current User Guilds [`GET /users/@me/guilds`](/developers/resources/user#get-current-user-guilds) now includes each guild's `banner` field! This enables apps using OAuth2 with the `guilds` scope to display guild banners. ## User-Installed Apps General Availability Back in March, we announced [the beta for user-installed apps](/developers/change-log#userinstallable-apps-preview). After listening and making updates based on feedback from developers and modmins, we're excited to announce that user-installed apps are now considered generally available and can be used in all servers (regardless of size). With this update, there are a few API and behavioral updates for user-installed apps. ###### API Updates * `user_id` has been removed from the `interaction_metadata` field on messages. Instead, you can use the `id` field in the nested `user` object. See the [Message Interaction Metadata Object](/developers/resources/message#message-interaction-metadata-object) for details. * User-installed apps are now limited to creating a maximum of 5 [follow-ups](/developers/interactions/receiving-and-responding#followup-messages) when responding to interactions. This only affects the [Create Followup Message endpoint](/developers/interactions/receiving-and-responding#create-followup-message), and apps installed to the server are unaffected. * On [Interactions](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure), the value of `authorizing_integration_owners` is now correctly serialized as a string. Previously, the `"0"` value was incorrectly serialized as a number. * `app_permissions` on [Interactions](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) now correctly represents the permissions for user-installed apps. Previously, the value was incorrect for user-installed apps. * Updating a message can result in a `400` response if the content of the message was blocked by AutoMod, which may be particularly important for [deferred messages](/developers/interactions/receiving-and-responding#responding-to-an-interaction). * Interaction responses are no longer forced to be ephemeral for servers with over 25 members. ###### New `Use External Apps` Permission A new [`USE_EXTERNAL_APPS` (`1 << 50`) permission](/developers/topics/permissions#permissions-bitwise-permission-flags) was added, and is enabled for servers by default. The new permission lets modmins control whether user-installed apps can post public replies in a server. If `Use External Apps` is disabled and your app is *not* installed to the server, your app’s responses will be ephemeral for the end user. Read more in the [Moderating Apps on Discord Help Center article](https://support.discord.com/hc/en-us/articles/23957313048343-Moderating-Apps-on-Discord#h_01HZQQQEADYVN2CM4AX4EZGKHM). ###### Updated Defaults for New Apps * Newly-created apps now default to having both "User Install" *and* "Guild Install" [installation contexts](/developers/resources/application#installation-context) enabled. This can be updated in the **Installation** tab in an [app's settings](https://discord.com/developers/applications). * Newly-created apps now default to using the "Discord Provided Link" [install link](/developers/resources/application#install-links). This can be updated in the **Installation** tab in an [app's settings](https://discord.com/developers/applications). * If Discord Provided Link is selected as the install link type, `application.commands` scope is added to both installation contexts. ## Premium Apps: New Premium Button Style & Deep Linking URL Schemes **New Premium Button Style** Introduces a new `premium` [button style](/developers/components/reference#button-button-styles) to be used with a `sku_id` which points to an active [SKU](/developers/resources/sku#sku-object). This allows developers to customize their premium experience by returning specific subscription or one-time purchase products. Learn more about using [button components with interactions](/developers/components/reference#button). This change deprecates Interaction Response Type 10 The `PREMIUM_REQUIRED (10)` interaction response type is now deprecated in favor of using custom premium buttons. This will continue to function but may be eventually unsupported. It is recommended to migrate your bots to use the more flexible [premium button component](/developers/components/reference#button-button-styles). Learn more about [gating features with premium interactions](/developers/monetization/implementing-app-subscriptions#prompting-users-to-subscribe). **Deep Linking URL Schemes for SKUs and Store** Introduces two new url schemes for linking directly to the Application Directory. When these links are used in chat, they are rendered as rich embeds that users can interact with to launch an app's store or open a SKU detail modal. * New [Store URL Scheme](/developers/monetization/managing-skus#linking-to-your-store): `https://discord.com/application-directory/:appID/store` * New [SKU URL Scheme](/developers/monetization/managing-skus#linking-to-a-specific-sku): `https://discord.com/application-directory/:appID/store/:skuID` ## Auto Moderation Member Profile Rule * Add Auto Moderation `MEMBER_PROFILE` rule [trigger\_type](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types). This rule type will check if a member's profile contains disallowed keywords. * Add Auto Moderation `BLOCK_MEMBER_INTERACTION` [action type](/developers/resources/auto-moderation#auto-moderation-action-object-action-types) currently available for the `MEMBER_PROFILE` rule [trigger\_type](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types). This action will "quarantine" the member to some extent and prevent them from performing most interactions within a specific server. ## Premium Apps: One-Time Purchases and Store Two new features are now available for Premium Apps: One-Time Purchases and Stores. **One-Time Purchases** * **Durable Items**: A one-time purchase that is permanent and is not subject to either renewal or consumption, such as lifetime access to an app's premium features. * **Consumable Items**: A one-time, non-renewable purchase that provides access, such as a temporary power-up or boost in a game. Learn more about [Implementing One-Time Purchases](/developers/monetization/implementing-one-time-purchases). **A Store for Your Premium App** We have also introduced a Store for your Premium App to showcase your app subscriptions and one-time purchase items. You can now create a unique Store page within the developer portal and add your published subscription SKUs or one-time purchase SKUs to your store view, allowing your users to buy these items from your App Directory or Bot User Profile. To explore these features, eligibility details, and how to enable monetization for your app, check out the [Monetization Overview](/developers/monetization/overview). **API Documentation Updates** The following were added to our public Monetization documentation with this update: * New [SKU Object Types](/developers/resources/sku#sku-object-sku-types) * New [Entitlement Object Types](/developers/resources/entitlement#entitlement-object-entitlement-types) * [Consume an Entitlement](/developers/resources/entitlement#consume-an-entitlement) API endpoint * `consumed` field on the [Entitlement](/developers/resources/entitlement) resource ## Modify Guild Member flags field permissions Update permissions necessary to modify the `flags` field when calling the [Modify Guild Member](/developers/resources/guild#modify-guild-member) endpoint. ## CSV Export for Premium App Analytics For apps with [Monetization](/developers/monetization/overview) enabled, we have released the ability to export your SKU analytics to CSV. These exports allow you to use your preferred data tools to report on your premium offerings. You can find the export at the bottom of the `Monetization → Analytics` tab of your app to export data points such as `sales_count`, `sales_amount`, `sales_currencies`, `cancellation_count`, `refund_amount`, and `refund_count`, aggregated by each of your offerings for the selected month. ## Discord Activities: Developer Preview of the Embedded App SDK Discord Developers can now build Activities! Activities are interactive, multiplayer experiences that run in an iframe in Discord. In order to make the communication between your experience and Discord, we've introduced the Embedded App SDK to assist in communicating between your app and the Discord client. * New [Discord Activities](/developers/activities/overview) developer docs with a tutorial, code samples, development guides, and design principles. * The Embedded App SDK is now available via [npm](https://npmjs.com/package/@discord/embedded-app-sdk) and [GitHub](http://github.com/discord/embedded-app-sdk). * The [Embedded App SDK Reference](/developers/developer-tools/embedded-app-sdk) is now available. To learn more about how to get started building your own Activity, check out the [Activities Overview](/developers/activities/overview). ## User-Installable Apps Preview Apps can now be installed to users—making them easier to install, discover, and access across Discord. User-installed apps can be used across all of a user's servers, within their (G)DMs, and in DMs with the app's bot user. When creating or updating your app, you can choose which installation types your app supports on the **Installation** page in your [app's settings](https://discord.com/developers/applications). To quickly get started, you can follow the new [Developing a User-Installable App tutorial](/developers/tutorials/developing-a-user-installable-app) or read details about the new changes below. This change introduces new concepts and fields across the API that apps will now encounter. ###### API Changes **Concepts:** * [Installation context](/developers/resources/application#installation-context) defines how an app was installed: to a user, a guild (server), or both. Currently, apps will default to only support the guild installation context, but the default may change in the future. * Commands can also support one or both installation contexts, with the default being the same as the app's supported installation context(s) at the time of command creation. * [Interaction context](/developers/interactions/application-commands#interaction-contexts) defines where a command can be used in Discord—within guilds, DM with your app's bot user, and/or within group DMs and DMs other than with your app's bot user. * The installation flow for apps have been updated so users can select whether they want to install an app to their account or to a server. **API Fields:** * New `integration_types_config` field for [Applications](/developers/resources/application#application-object) include the default scopes and permissions for app's supported installation contexts * New `integration_types` and `contexts` fields for [Commands](/developers/interactions/application-commands#application-command-object-application-command-structure) are the supported [installation](/developers/interactions/application-commands#installation-context) and [interaction](/developers/interactions/application-commands#interaction-contexts) contexts (respectively) for the command. Read [command contexts](/developers/interactions/application-commands#contexts) documentation for details. * New `context` field for [Interactions](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) indicates the [interaction context](/developers/interactions/application-commands#interaction-contexts) where an interaction was triggered from. * New `authorizing_integration_owners` field for [Interactions](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) includes a mapping of installation contexts that the interaction was authorized for, to related snowflakes for that context. Read [Authorizing Integration Owners Object](/developers/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object) for details. * `app_permissions` is now always serialized for interactions to indicate what [permissions](/developers/topics/permissions#permissions-bitwise-permission-flags) your app has access to in the context its' responding. For (G)DMs with other users, it will include the `ATTACH_FILES | EMBED_LINKS | MENTION_EVERYONE`, and for DMs with the app's bot user it will also contain `USE_EXTERNAL_EMOJIS` for the bot’s DM * New `interaction_metadata` on [Messages](/developers/resources/message#message-object) that are created as part of an interaction response (either a response or follow-up). See [Message Interaction Metadata Object](/developers/resources/message#message-interaction-metadata-object) for details. * `dm_permission` field for [Commands](/developers/interactions/application-commands#application-command-object-application-command-structure) is deprecated. Apps should use `contexts` instead. * `interaction` field for [Messages](/developers/resources/message#message-object) is deprecated. Apps should use `interaction_metadata` instead. ###### Limitations and Known Issues * During the preview, interaction responses for the user installation context will be forced to be ephemeral in servers with over 25 members. Forced ephemerality is enforced at the client-level, so your app does not need to manually pay attention to server size, and will not receive errors via the API. * All [follow-up messages](/developers/interactions/receiving-and-responding#followup-messages) are currently forced to be ephemeral in DMs * Follow-up messages have a bug where they will not correctly respect user permissions ## Guild Prune Requiring The [Get Guild Prune Count](/developers/resources/guild#get-guild-prune-count) and [Begin Guild Prune](/developers/resources/guild#begin-guild-prune) endpoints now require the `MANAGE_GUILD` permission alongside the existing `KICK_MEMBERS` requirement. ## Enforced Nonces on Create Message Endpoint The [Create message](/developers/resources/message#create-message) endpoint now supports an `enforce_nonce` parameter. When set to true, the message will be deduped for the same sender within a few minutes. If a message was created with the same nonce, no new message will be created and the previous message will be returned instead. This behavior will become the default for this endpoint in a future API version. ## Limit Number of Fields in Embeds [Embed objects](/developers/resources/message#embed-object) are now limited more explicitly to 25 [embed fields](/developers/resources/message#embed-object-embed-field-structure). If you pass more than 25 fields within the an embed's `fields` property, an error will be returned. Previously, only the first 25 embed fields would be displayed within the embed but no error was returned. ## Clarification on Permission Splits for Expressions and Events The existing behavior for `MANAGE_GUILD_EXPRESSIONS` and `MANAGE_EVENTS` will **not be changing**. These permissions will continue to allow your bot users to create, update and delete expressions/events. No action will be needed if you plan to continue using these permissions. To support added controls for expressions and events, new [permissions](/developers/topics/permissions) were added for users and roles in July 2023: * `CREATE_GUILD_EXPRESSIONS`: `1 << 43` * `CREATE_EVENTS`: `1 << 44` These allow for creating new expressions and events, as well as editing and deleting those created by the current user. These were rolled out in July 2023 to users and roles and have been added to our developer documentation but **are not yet available to app developers**. We will share an update here when these new permissions are available in your apps. ## Experimenting with End-to-End Encryption for Voice & Video #### What’s Happening? As outlined in [a blog post earlier this year](https://discord.com/blog/encryption-for-voice-and-video-on-discord), we are experimenting with end-to-end encryption (e2ee) for voice and video channels. End-to-end encryption is designed to only allow the participants in a call to decipher its contents. One of the protocols we’re experimenting with is called Messaging Layer Security, which we believe would allow us to deliver end-to-end encryption at scale. Intermediaries, including platforms like Discord, are unable to access the content of communications encrypted with end-to-end encryption. #### How do I prepare for the changes? During this testing phase, there is nothing developers need to do to support end-to-end encryption. Voice channels will automatically downgrade to documented, non-e2ee protocols when a bot user joins the channel. This is transparent to the connecting client but may result in a slight delay between establishing a connection and receiving audio. #### What is planned for the future? We will be continuing our testing and will share updates along with developer documentation and sample code once it is available. Once this information is published, we will provide developers with a substantial timeframe to implement end-to-end encryption when interacting with voice and video. ## Premium App Subscriptions: New Ways for Testing App Subscriptions Following feedback on Premium App Subscriptions, we've made it easier for developers to test their app subscriptions. The goal is to provide you with flexibility during testing and prevent you from having to use live payment methods. * Team members will automatically receive a 100% discount on a subscription for your app, allowing you to test the end-to-end payment flow * Developers can create and delete [test entitlements](/developers/resources/entitlement#create-test-entitlement) to toggle access to an application's premium features Read more about [Testing your App Subscriptions Implementation](/developers/monetization/implementing-app-subscriptions#testing-your-app-subscription-implementation) for details. ## Fix Message Edit Interaction Response Permissions Behavior for message edit interaction response actions like [updating interaction responses](/developers/interactions/receiving-and-responding#edit-original-interaction-response) and [sending follow-up messages](/developers/interactions/receiving-and-responding#followup-messages) have been updated to follow a bot user's permissions. Previously, some message edit interaction response actions would use the default permissions rather than a bot user's permissions. ## Premium App Subscriptions Now Available in the EU and UK Starting today, eligible developers based in EU and UK can now monetize their verified apps with App Subscriptions. [App Subscriptions](/developers/monetization/overview) let you to charge your users for premium functionality with a recurring, monthly subscription. New features for Premium App Subscriptions are documented in the [App Subscriptions overview](/developers/monetization/overview) and in [the changelog for the previous App Subscriptions release](/developers/change-log#premium-app-subscriptions-available-in-the-us). To learn more about eligibility details and how to enable monetization for your app, check out the [Monetization Overview](/developers/monetization/overview). ## Global Rate Limit added to discordapp.com/\* We have added a global rate limit for API requests made to `discordapp.com/*` and may further restrict requests in the future. To limit impact on your app, please make sure you are making calls to `discord.com/*`. This does **not** apply for `cdn.discordapp.com`. Refer to the [API Reference](/developers/reference) for more info on which url(s) to use when building on the REST API * [February 14, 2022 Change Log](/developers/change-log#api-v10): Requests to v10 and higher will no longer be supported on `discordapp.com` (this does not affect `cdn.discordapp.com`) * [May 4, 2020 #api-announcements](https://discord.com/channels/613425648685547541/697138785317814292/706944540971630662) ## Premium App Subscriptions Available in the US Starting today, eligible US-based developers can monetize their verified apps with App Subscriptions. [App Subscriptions](/developers/monetization/overview) let you to charge your users for premium functionality with a recurring, monthly subscription. * Manage subscription SKUs in the Developer Portal * View monetization analytics in the Developer Portal * Team owners can setup and manage payouts in Developer Portal * New endpoints for working with [SKUs](/developers/resources/sku) and [Entitlements](/developers/resources/entitlement): * [List SKUs](/developers/resources/sku#list-skus) `GET /applications//skus` * [List Entitlements](/developers/resources/entitlement#list-entitlements) `GET /applications//entitlements` * [Create Test Entitlement](/developers/resources/entitlement#create-test-entitlement) `POST /applications//entitlements` * [Delete Test Entitlement](/developers/resources/entitlement#delete-test-entitlement) `DELETE /applications//entitlements/` * [Gateway Events](/developers/events/gateway-events#entitlements) for working with entitlements: `ENTITLEMENT_CREATE`, `ENTITLEMENT_UPDATE`, `ENTITLEMENT_DELETE` * New [`PREMIUM_REQUIRED (10)` interaction response type](/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type) is available to prompt users to upgrade * New `entitlements` field, which is an array of [entitlement](/developers/resources/entitlement) objects, available in interaction data payloads when [receiving and responding to interactions](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) To learn more about eligibility details and how to enable monetization for your app, check out the [Monetization Overview](/developers/monetization/overview). ## Default Value in Auto-populated Select Menus A new `default_values` field was added for user (`5`), role (`6`), mentionable (`7`), and channel (`8`) [select menu components](/developers/components/reference). `default_values` is a list of [default value objects](/developers/components/reference#user-select-select-default-value-structure), which each include an `id` (the snowflake value for the resource), as well as a corresponding `type` (either `"user"`, `"role"`, or `"channel"`). ## Team Member Roles You can now select roles other than admin when inviting users or configuring members of a team. There are four [role types](/developers/topics/teams#team-member-roles-team-member-role-types) that a team member can be assigned: owner, admin, developer, or read-only. The team member object now has an additional [`role` field](/developers/topics/teams#data-models-team-member-object), which is a string representing the member's current role. Details about team member roles are in the updated [Teams documentation](/developers/topics/teams#team-member-roles). ## Embed Debugger We've released a new [Embed Debugger tool](https://discord.com/developers/embeds) that shows you how a URL's metadata will be parsed and rendered as a link embed within the Discord client. Use it to preview your site's embed, or debug why your site's link embed isn't working as expected. ## Activity State for Bot Users The `state` field in [activity objects](/developers/events/gateway-events#activity-object) can now be set when [updating presence](/developers/events/gateway-events#update-presence) for a bot user. The value of `state` will appear as a custom status for the bot user when an [activity's `type`](/developers/events/gateway-events#activity-object-activity-types) is set to `4`, or as additional data under an activity's name for other activity types. ## Public Preview of OpenAPI 3.1 Specification We're introducing an [OpenAPI 3.1 spec](https://github.com/discord/discord-api-spec) in public preview to make it easier and more reliable to develop with the HTTP API. While our current developer documentation requires manual reviews and updates, the OpenAPI spec is generated from the source code which means it better reflects the nooks, crannies, and nuances of the Discord API. The public preview of the OpenAPI spec is subject to breaking changes without advance notice, and should not be used within production environments. If you see something that looks incorrect or can be improved, you can [open an issue](https://github.com/discord/discord-api-spec/issues). The public spec can be found in the new [`discord-api-spec` repository on GitHub](https://github.com/discord/discord-api-spec). ## New GUILD\_MEDIA channel type * Add the [`GUILD_MEDIA` (16) channel type](/developers/resources/channel#channel-object-channel-types). `GUILD_MEDIA` channels only support threads, similar to `GUILD_FORUM` channels. Read the [media channel topic](/developers/topics/threads#media-channels) for more information on the relevant APIs and technical details, or the [media channel Help Center Article](https://creator-support.discord.com/hc/en-us/articles/14346342766743) for more about the feature. ## Add Join Raid and Mention Raid fields * Add Auto Moderation `mention_raid_protection_enabled` [trigger\_metadata](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata) field for the `MENTION_SPAM` [trigger\_type](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types). If this field and its parent `MENTION_SPAM` rule are enabled, Auto Moderation provides baseline detection against sudden spikes in mention activity that are normally indicative of mention raids. * Add `safety_alerts_channel_id` [guild](/developers/resources/guild#guild-object) field and [`RAID_ALERTS_DISABLED` guild feature flag](/developers/resources/guild#guild-object-guild-features) which are associated with join raid protection ## Unique usernames on Discord Bot users will stay on the legacy username system for now. More details can be found on the [Developer Help Center article](https://dis.gd/app-usernames). Discord’s username system is changing. Discriminators are being removed and new, unique usernames and display names are being introduced. You can read more details about how changes to the username system affects non-bot users in the [general Help Center article](https://dis.gd/usernames). To learn how it impacts bot users specifically, you can read the [Developer Help Center article](https://dis.gd/app-usernames). This changelog focuses only on the technical changes to be aware of to update your app's code. ### Identifying migrated users The new username system will rollout to users over time rather than all at once. The value of a single zero (`"0"`) in the [`discriminator` field](/developers/resources/user#user-object-user-structure) on a user will indicate that the user has been migrated to the new username system. Note that the discriminator for migrated users will *not* be 4-digits like a standard discriminator (it is `"0"`, not `"0000"`). The value of the `username` field will become the migrated user's unique username. After migration of all users is complete, the `discriminator` field may be removed. #### Example migrated user ```json theme={"system"} { "id": "80351110224678912", "username": "nelly", "discriminator": "0", "global_name": "Nelly", "avatar": "8342729096ea3675442027381ff50dfe", "verified": true, "email": "nelly@discord.com", "flags": 64, "banner": "06c16474723fe537c283b8efa61a30c8", "accent_color": 16711680, "premium_type": 1, "public_flags": 64 } ``` ### Display names As part of the new username system, standard Discord users can define a non-unique display name. This value will be a new `global_name` field with a max length of 32 characters. If the user has not set a display name, `global_name` will be null. ### Default avatars For users with migrated accounts, default avatar URLs will be based on the user ID instead of the discriminator. The URL can now be calculated using `(user_id >> 22) % 6`. Users on the legacy username system will continue using `discriminator % 5`. ## Bot users added to all new apps Starting today, [bot users](/developers/topics/oauth2#bot-vs-user-accounts) will be added to all newly-created apps. Settings and configuration options for bot users remain the same, and can still be accessed on the **Bot** page within your [app's settings](https://discord.com/developers/applications). If your app doesn't need or want a bot user associated with it, you can refrain from adding the [`bot` scope](/developers/topics/oauth2#shared-resources-oauth2-scopes) when installing your app. ## Interaction Channel Data Interactions now contain a `channel` field which is a partial channel object and guaranteed to contain `id` and `type`. We recommend that you begin using this channel field to identify the source channel of the interaction, and may deprecate the existing `channel_id` field in the future. See the [interaction documentation](/developers/interactions/receiving-and-responding#interaction-object) for more details. ## Add Auto Moderation custom\_message Action Metadata Field Add new `custom_message` [action metadata](/developers/resources/auto-moderation#auto-moderation-action-object-action-metadata) for the `BLOCK_MESSAGE` [action type](/developers/resources/auto-moderation#auto-moderation-action-object-action-types)). You can now specify a custom string for every Auto Moderation rule that will be shown to members whenever the rule blocks their message. This can be used as an additional explanation for why a message was blocked and as a chance to help members understand your server's rules and guidelines. ## Update to Locked Threads ### Upcoming Changes Currently, threads in Discord (including forum posts) can either be archived or both locked and archived. Starting on **March 6, 2023**, threads will be able to be locked *without* being archived, which will slightly change the meaning of the [`locked` field](/developers/resources/channel#thread-metadata-object-thread-metadata-structure). `locked` currently indicates that a thread cannot be reopened by a user without the [`MANAGE_THREADS` (`1 << 34`) permission](/developers/topics/permissions#permissions-bitwise-permission-flags), but it doesn't restrict user activity within active (meaning non-archived) threads. After this change, users (including bot users) without the `MANAGE_THREADS` permission will be more restricted in locked threads. Users won't be able to create or update messages in locked threads, or update properties like its title or tags. Additionally, some user activity like deleting messages and adding or removing reactions will *only* be allowed in locked threads if that thread is also active (or un-archived). If a user or bot user has the `MANAGE_THREADS` permission, they will still be able to make changes to the thread and messages. The upcoming change does not affect the meaning of the [`archived` field](/developers/resources/channel#thread-metadata-object-thread-metadata-structure) or the behavior of a thread that is both locked and archived. ### How do I prepare for this change? If your app is interacting with threads (including forum posts), it should check the state of the `locked` and/or `archived` field for the thread to understand which actions it can or cannot perform. It should also be prepared to handle any errors that it may receive when a thread is locked. ## Increase Auto Moderation Keyword Limits * Increase maximum number of rules with `KEYWORD` [trigger\_type](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types) per guild from 5 to 6 * Increase maximum length for each keyword in the `keyword_filter` and `allow_list` [trigger\_metadata](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata) fields from 30 to 60. ## Guild Audit Log Events At long last, a new [`GUILD_AUDIT_LOG_ENTRY_CREATE`](/developers/events/gateway-events#guild-audit-log-entry-create) event has been added to the gateway, allowing your application to react to moderation actions in guilds. The `VIEW_AUDIT_LOG` permission is required in order to receive these events, and the [`GUILD_MODERATION` intent](/developers/events/gateway#gateway-intents) needs to be set when connecting to the gateway. ## Thread Member Details and Pagination A new `member` field was added to the [thread member object](/developers/resources/channel#thread-member-object). `member` is a [guild member object](/developers/resources/guild#guild-member-object) that will be included within returned thread member objects when the new `with_member` field is set to `true` in the [List Thread Members](/developers/resources/channel#list-thread-members) (`GET /channels//thread-members`) and [Get Thread Member](/developers/resources/channel#get-thread-member) (`GET /channels//thread-members/`) endpoints. Setting `with_member` to `true` will also enable pagination for the [List Thread Members](/developers/resources/channel#list-thread-members) endpoint. When the results are paginated, you can use the new `after` and `limit` fields to fetch additional thread members and limit the number of thread members returned. By default, `limit` is 100. #### Upcoming Changes Starting in API v11, [List Thread Members](/developers/resources/channel#list-thread-members) (`GET /channels//thread-members`) will *always* return paginated results, regardless of whether `with_member` is passed or not. ## Add Default Layout setting for Forum channels `default_forum_layout` is an optional field in the [channel object](/developers/resources/channel) that indicates the default layout for posts in a [forum channel](/developers/topics/threads#forums). A value of 1 (`LIST_VIEW`) indicates that posts will be displayed as a chronological list, and 2 (`GALLERY_VIEW`) indicates they will be displayed as a collection of tiles. If `default_forum_layout` hasn't been set, the value will be `0`. Setting `default_forum_layout` requires the `MANAGE_CHANNELS` permission. ## Add Application Connections Metadata and Linked Roles Introducing [linked roles](https://discord.com/blog/connected-accounts-functionality-boost-linked-roles) as well as the ability for all developers to set up their own linked roles with an application. This includes: * New [`role_connections_verification_url`](/developers/resources/application#application-object) that can be set in the developer portal in order for the application to render as potential verification option for linked roles. * [Application metadata](/developers/resources/application-role-connection-metadata#application-role-connection-metadata-object) to specify more detailed linked role requirements. * New endpoints to [retrieve](/developers/resources/application-role-connection-metadata#get-application-role-connection-metadata-records) (`GET /applications//role-connections/metadata`) and [update](/developers/resources/application-role-connection-metadata#update-application-role-connection-metadata-records) (`PUT /applications//role-connections/metadata`) application connection metadata. * New [`role_connections.write`](/developers/topics/oauth2#shared-resources-oauth2-scopes) OAuth2 scope required to authenticate the below requests. * Endpoints to [retrieve](/developers/resources/user#get-current-user-application-role-connection) (`GET /users/@me/applications/{application.id}/role-connection`) and [update](/developers/resources/user#update-current-user-application-role-connection) (`PUT /users/@me/applications/{application.id}/role-connection`) a user's role connections, both of which return an [application role connection](/developers/resources/user#application-role-connection-object) object. For a quick rundown on how to get started using linked roles, refer to the [tutorial](/developers/tutorials/configuring-app-metadata-for-linked-roles). ## Add Auto Moderation Allow List for Keyword Rules and Increase Max Keyword Rules Per Guild Limit * Auto Moderation rules with [trigger\_type](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types) `KEYWORD` now support an `allow_list` field in its [trigger\_metadata](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata). Any message content that matches an `allow_list` keyword will be ignored by the Auto Moderation `KEYWORD` rule. Each `allow_list` keyword can be a multi-word phrase and can contain [wildcard symbols](/developers/resources/auto-moderation#auto-moderation-rule-object-keyword-matching-strategies). * Increase maximum number of rules with `KEYWORD` [trigger\_type](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types) per guild from 3 to 5 * Increase maximum length for each regex pattern in the `regex_patterns` [trigger\_metadata](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata) field from 75 to 260. ## Upcoming Application Command Permission Changes Based on feedback, we’re updating permissions for [application commands](/developers/interactions/application-commands) to simplify permission management and to make command permissions more closely resemble other permissions systems in Discord. Server admins can begin to opt-in to the command permission changes outlined here on a per-server basis **starting on December 16, 2022**. However, changes will not be applied to all servers **until late January or early February**. Current permissions behavior is documented in [the application commands documentation](/developers/interactions/application-commands#permissions) and in [the changelog for the previous permissions update](/developers/change-log#updated-command-permissions) These changes are focused on how configured permissions are used by Discord clients, so most apps will be unaffected. However, if your app uses the [Update Permissions endpoint](/developers/interactions/application-commands#edit-application-command-permissions) (`PUT /applications//guilds//commands//permissions`), you may need to make updates and should read these changes carefully. #### Types of command permission configurations The following information isn’t changing, but it’s helpful context to understand the changes. Discord’s clients determine whether a user can see or invoke a command based on three different permission configurations: * **Command-level permissions** are set up by an admin for a specific *command* in their server. These permissions affect only a specific command. * **App-level permissions** are set up by an admin for a specific *app* in their server. These permissions affect all commands for an app. * **`default_member_permissions`** are set up by an app when creating or updating a command. `default_member_permissions` apply to that command in *all* servers (unless an override exists). More information about `default_member_permissions` is [in the documentation](/developers/interactions/application-commands#application-command-permissions-object-using-default-permissions). The concepts of these permission configurations are not changing. But then of course, the question becomes… ### What's changing? There are two changes around command permissions: 1. The logic used to apply permission configurations to a user in a given context within Discord clients 2. New `APPLICATION_COMMAND_PERMISSIONS_V2` guild feature flag to indicate whether that guild is using the old permissions logic or the new (upcoming) logic. Let's go deeper into both of these. #### 1. How permission configurations are applied in Discord ##### Current behavior: Currently, these systems are **mutually-exclusive**, meaning that only one type of permission configuration is used to determine whether a user can invoke a command. With this current system, there is a clear hierarchy: command-level permission configurations take precedence (if present), then app-level permission configurations (if present), and finally `default_member_permissions` if neither are present. The implication of the current permissions system means that: * If any command-level permissions are configured, all app-level permissions and `default_member_permissions` are ignored for that command. * If any app-level permissions are configured, `default_member_permissions` is ignored for *all* of that app’s commands. This system leads to unintentional permission escalations, and can force moderators to manually re-define their app-level configurations to make small tweaks on the command-level. ##### Upcoming behavior: The new system removes the mutual exclusion aspect, meaning that the different types of permission configurations work together rather than independently—specifically, more than one may be used to determine whether a user can invoke a command. **`default_member_permissions` continues to act as a “default” that a developer can set when creating or updating a command.** **App-level permission configurations now act as the "base" configuration.** App-level configurations define who is allowed to use the app and where. These will work *together* with `default_member_permissions`, meaning if a user is granted access via an app-level permission configuration, they will still be restricted to the `default_member_permissions` for each command (by default). No more accidentally granting `/ban` which requires `BAN_MEMBERS` to `@BotMemers` just because you gave them access to the app! **Command-level permission configurations now act as an “override” of the app-level.** Command-level configurations override what is present at the app-level *and* any restrictions set by `default_member_permissions`. This means that an admin can explicitly grant a user access to a specific command even if they are denied access on the app-level *or* if they don't have permissions that meet that command's `default_member_permissions`. If a command-level configuration does not exist for the given context, the system will fall back to looking at the app-level configuration. ##### Flowchart for command permissions logic Below is a simplified flowchart that illustrates how permissions will be applied by the Discord client after the new changes take effect. Flowchart with an overview of the new permissions configurations logic #### 2. `APPLICATION_COMMAND_PERMISSIONS_V2` Guild Feature We added a new [`APPLICATION_COMMAND_PERMISSIONS_V2` feature flag](/developers/resources/guild#guild-object-guild-features) which indicates whether that server is using **the current permissions logic**. * If the flag *is* present, that server is using the old command permissions behavior. * If the flag *is not* present, that server has migrated from the old command permissions behavior to the new behavior. ### Am I affected? Your app will only be affected if it uses the [`PUT /applications//guilds//commands//permissions`](/developers/interactions/application-commands#edit-application-command-permissions) endpoint. This is a pretty restricted endpoint used to manage and update application command permissions on behalf of admins, meaning that it requires the `applications.commands.permissions.update` scope. **If your app doesn’t use this endpoint, there’s nothing you need to prepare for these changes.** If your app does use this endpoint, you should read the section on preparing for changes below. ### How do I prepare for the changes? To prepare for these changes, you should take two steps: **1. Use the `APPLICATION_COMMAND_PERMISSIONS_V2` flag** Use this flag to determine which permissions logic that server is using. While the transition from the old behavior to the new behavior is happening, you may need two code paths depending on if the flag is present or not. ```py theme={"system"} if 'APPLICATION_COMMAND_PERMISSIONS_V2' in guild.features: # Use current behaviors when interacting with endpoint else: # Use new permissions behaviors when interacting with endpoint ``` If you don’t have access to guild features already through Gateway events, you can fetch that information using the [`GET /guilds/` endpoint](/developers/resources/guild#get-guild). **2. Modify the behavior based on your use case** After you know what permissions behavior the server is using, you should update how you handle that server specifically. To understand what changes you need to make, you should look at the assumptions users have when your app updates their server’s commands permissions. Do you have a web dashboard where admins update permissions? If so, analyze the logic of that dashboard and what your permission configurations are trying to do to map them to the new permissions behavior. Do you document what your app is doing in regards to certain command permissions you’re configuring on behalf of the admin? If so, map that documentation to the new behavior. If you are unsure, you can communicate with your admin users to ask if your new logic meets their expectations. #### What happens if I don’t update my app? If your app is affected and you don’t update it, permissions behavior that your app configures may not match what you or the users of your app expect. #### How long do I have to update my app? The new `APPLICATION_COMMAND_PERMISSIONS_V2` flag is already live, and you should start seeing it in guilds’ feature flags. The new permissions behavior will roll out **on December 16, 2022**. On this date, admins will begin to see a banner that allows them to *optionally* move their server to the new behavior. In **late January or early February**, all servers will be migrated to the new behavior. We'll post another changelog at this point, at which time you can remove any logic around the old permissions behavior. ## GameSDK Feature Deprecation To help keep us focused on the features, improvements, and gaming-related experiences that Discord users love, we are deprecating the following pieces of the GameSDK **starting today**, and decommissioning them on **Tuesday, May 2, 2023**: * [Achievements](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Achievements.md) * [Applications](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Applications.md) * [Voice](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Discord_Voice.md) * [Images](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Images.md) * [Lobbies](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Lobbies.md) * [Networking](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Networking.md) * [Relationships](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Relationships.md) * [Storage](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Storage.md) * [Store](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Store.mdmd) This deprecation period will last until **Tuesday May 2, 2023**, after which these pieces will be decommissioned and no longer work. The other pieces of the GameSDK will continue to be supported. We know that Discord is an important place for people to find belonging, and that using your Discord identity in games is a crucial part of that sense of belonging. You’ll still be able to use the GameSDK to integrate Rich Presence, relationships, entitlements, basic user information, and the overlay. ## Add Auto Moderation Regex Support Auto Moderation rules with [trigger\_type](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types) `KEYWORD` now support a `regex_patterns` field in its [trigger\_metadata](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types). Regex patterns are a powerful way to describe many keywords all at once using one expression. Only Rust flavored regex is supported, which can be tested in online editors such as [Rustexp](https://rustexp.lpil.uk/). ## Delete Ephemeral Messages Ephemeral interaction responses and follow-ups can now be deleted with a valid interaction token using the following endpoints: * [`DELETE /webhooks///messages/@original`](/developers/interactions/receiving-and-responding#delete-original-interaction-response) * [`DELETE /webhooks///messages/`](/developers/interactions/receiving-and-responding#delete-followup-message) As a reminder, interaction tokens stay valid for up to 15 minutes after the interaction occurs. Details can be found in the [interaction documentation](/developers/interactions/receiving-and-responding). ## New Select Menu Components Four new select menu [component types](/developers/components/reference#component-object-component-types) have been added to make it easier to populate selects with common resources in Discord: * User select (type `5`) * Role select (type `6`) * Mentionable (user *and* role) select (type `7`) * Channel select (type `8`) The new select menu components are defined similarly to the existing string select menu—with the exception of not including the `options` field and, within channel select menus, having the option to include a `channel_types` field. The [select menu interaction](/developers/components/reference#string-select-string-select-interaction-response-structure) apps receive also contain a [`resolved` field](/developers/interactions/receiving-and-responding#interaction-object-resolved-data-structure) for the new components. More details can be found in the updated [select menu documentation](/developers/components/reference#component-object-component-types). ## Default Sort Order for Forum Channels `default_sort_order` is an optional field in the [channel object](/developers/resources/channel) that indicates how the threads in a [forum channel](/developers/topics/threads#forums) will be sorted for users by default. Setting `default_sort_order` requires the `MANAGE_CHANNELS` permission. If `default_sort_order` hasn't been set, its value will be `null`. ## Auto Moderation Spam and Mention Spam Trigger Types Two new [trigger types](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-types) were added to Auto Moderation: * `MENTION_SPAM` blocks messages that mention more than a set number of unique server members or roles. Apps can define the number (up to 50) using the `mention_total_limit` field in the [trigger metadata object](/developers/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata) when creating or updating an Auto Moderation rule. * `SPAM` blocks links and messages that are identified as spam. More information can be found in the [Auto Moderation documentation](/developers/resources/auto-moderation). ## Forum Channels Release Forum channels ([`GUILD_FORUM` or `15`](/developers/resources/channel#channel-object-channel-types)) have been released to all community servers. `GUILD_FORUM` channels are a new channel type that only supports threads, which display differently than in text (`GUILD_TEXT`) channels. Check out the [forums topic](/developers/topics/threads#forums) for more information on the relevant APIs and technical details, and the [Forums FAQ](https://support.discord.com/hc/en-us/articles/6208479917079-Forum-Channels-FAQ#h_01G69FJQWTWN88HFEHK7Z6X79N) for more about the feature. ## Message Content is a Privileged Intent As of today, [message content](/developers/events/gateway#message-content-intent) is a privileged intent for all verified apps *and* apps eligible for verification. More details about why it's becoming a privileged intent and how to apply for it is in the [Help Center FAQ](https://support-dev.discord.com/hc/articles/4404772028055-Message-Content-Privileged-Intent-FAQ). Any app that does not have the message content intent configured in its app's settings within the Developer Portal will receive empty values in fields that expose message content across Discord's APIs (including the `content`, `embeds`, `attachments`, and `components` fields). These restrictions do not apply for messages that a bot or app sends, in DMs that it receives, or in messages in which it is mentioned. #### If your app is verified Verified apps and verification-eligible apps must be approved for the message content intent to receive message content. If your verified app isn’t approved, or doesn’t account for the new message content restrictions, it will break for users. ##### Temporary Message Content Intent Verified apps or apps that have submitted for verification can temporarily opt-in to a grace period which will allow your app to continue receiving message content until October 1. However, if you opt-in to the grace period, your app will be prevented from joining any additional servers until you opt-out. More details are in the [Help Center article](https://support-dev.discord.com/hc/en-us/articles/8561391080471). #### If your app is unverified Unverified apps must still must enable the intent in your app’s settings within the Developer Portal. Existing unverified apps will automatically have the message content intent toggled on in their settings. New unverified apps will have to manually toggle the intent in the Developer Portal. ## Slash Command Mentions This week, [Slash Command mentions](/developers/reference#message-formatting) are rolling out across all Discord clients (for Android, mentions are limited to the [React Native client](https://discord.com/blog/android-react-native-framework-update)). Clicking a Slash Command mention will auto-populate the command in the user's message input. Slash Command mentions use the following format: ``. You can also use `` and `` for subcommands and subcommand groups. ## Session-specific Gateway Resume URLs Starting on **September 12, 2022**, apps that aren’t using the new `resume_gateway_url` field to resume gateway sessions will be disconnected significantly faster than normal. A new `resume_gateway_url` field has been added to the [Ready](/developers/events/gateway-events#ready) gateway event to support session-specific gateway connections. The value of `resume_gateway_url` is a session-specific URL that should be used when resuming the gateway session after a disconnect. Previously, `wss://gateway.discord.gg` was used to connect *and* resume sessions, but should now only be used during the connection. At the moment, the value of `resume_gateway_url` will always be `wss://gateway.discord.gg` to give developers more time to adopt the new field. In the near future, the value will change to the session-specific URLs. ## Upcoming Permissions Change to Webhook Routes On August 8th, 2022 we will begin requiring the `VIEW_CHANNEL (1 << 10)` permission for webhook routes which require `MANAGE_WEBHOOKS (1 << 29)`, to align with our documented behavior. We don't expect that many applications will be affected by this, but in case you are, please ensure you have updated permissions needed for accessing the following routes: * [`GET /webhooks/{webhook.id}`](/developers/resources/webhook#get-webhook) * [`DELETE /webhooks/{webhook.id}`](/developers/resources/webhook#delete-webhook) * [`PATCH /webhooks/{webhook.id}`](/developers/resources/webhook#modify-webhook) * [`GET /channels/{channel.id}/webhooks`](/developers/resources/webhook#get-channel-webhooks) * [`POST /channels/{channel.id}/webhooks`](/developers/resources/webhook#create-webhook) ## Add Subcommand Groups and Subcommands to Message Interaction Objects While this is a breaking change, most apps only rely on interaction responses (`INTERACTION_CREATE`), *not* message interaction objects (`MESSAGE_CREATE`). [Interaction responses](/developers/interactions/receiving-and-responding#interaction-object-interaction-data) are unaffected by this change. #### Upcoming Changes Starting **July 18, 2022**, the `name` field for [message interaction objects](/developers/interactions/receiving-and-responding#message-interaction-object) will now include subcommands and subcommand groups in the value (along with the existing top-level command). In the future, we recommend not relying on this message interaction field. The format of the value will be the different command levels (if they exist), separated by spaces: ` ` The `name` field is only seen on messages that are a response to an interaction without an existing message, so interaction objects for message components don’t include this field. #### Updating your app Most apps only rely on interaction responses, not message interaction objects. We don't recommend that your app relies on the `name` field for message interactions objects, but if it does you should update your app to handle subcommands and subcommand groups that your app may encounter. As an example of the change, pretend your app had a command `/role` with subcommands `add` and `remove`. Currently, the `name` field in the original interaction payload would contain `role`. If you responded to that interaction with a message then fetched its contents, the `name` field for that message interaction object would contain `role` as well. After this change, the `name` field for the original interaction payload will still contain `role`. However, now if you responded to that interaction with a message then fetched its contents, the `name` field for that message interaction object would contain `role add` or `role remove`. ## Min and Max Length for Command Options Application [command options](/developers/interactions/application-commands#application-command-object-application-command-option-structure) of type `STRING` now includes optional `min_length` and `max_length` fields to control the length of text a user can input. The value of `min_length` must be greater or equal to `0`, and the value of `max_length` must be greater or equal to `1`. ## Calculated Permissions in Interaction Payloads Interaction payloads now contain an `app_permissions` field whose value is the computed [permissions](/developers/topics/permissions#permissions-bitwise-permission-flags) for a bot or app in the context of a specific interaction (including any channel overwrites). Similar to other permission fields, the value of `app_permissions` is a bitwise OR-ed set of permissions expressed as a string. Read details in the [interactions documentation](/developers/interactions/receiving-and-responding#interaction-object). For apps without a bot user (or without the `bot` scope), the value of `app_permissions` will be the same as the permissions for `@everyone`, but limited to the permissions that can be used in interaction responses (currently `ATTACH_FILES`, `EMBED_LINKS`, `MENTION_EVERYONE`, and `USE_EXTERNAL_EMOJIS`). ## Changes to Bot Permissions for Interactions and Webhooks #### Upcoming Changes `MENTION_EVERYONE`, `SEND_TTS_MESSAGES` and `USE_EXTERNAL_EMOJIS` are the only permissions that will be affected by this change. In a previous version of this changelog, it was indicated that `ATTACH_FILES` and `EMBED_LINKS` would be affected but this is no longer the case. Starting **August 3, 2022**, the way some of a bot's `MENTION_EVERYONE`, `SEND_TTS_MESSAGES` and `USE_EXTERNAL_EMOJIS` [permissions](/developers/topics/permissions) are calculated is changing in two cases: * When **responding to an [interaction](/developers/interactions/receiving-and-responding)** (like application commands or message components) * When **executing a [webhook](/developers/resources/webhook) that the bot created** Going forward, in the above cases, a bot’s `MENTION_EVERYONE`, `SEND_TTS_MESSAGES` and `USE_EXTERNAL_EMOJIS` permissions will be calculated based on the permissions its granted, *including* any [overwrites](/developers/topics/permissions#permission-overwrites). Previously, a bot’s permissions in these cases relied only on those granted to `@everyone`. This change *only* applies to bots. The permissions for an app without a bot user (or without the `bot` scope) will still depend on `@everyone`. #### Updating Your App If your bot wants to use the `MENTION_EVERYONE`, `SEND_TTS_MESSAGES` or `USE_EXTERNAL_EMOJIS` permissions when responding to interactions or executing a webhook, **ensure that the bot was installed (or explicitly granted) with them**. Note that even if your bot is installed with certain permissions, they can be changed using overwrites. For interactions, you can use the [`app_permissions` field](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) to determine your app or bot's contextual permissions before replying. ## Message Content in Auto Moderation events In API v10, the `MESSAGE_CONTENT` (`1 << 15`) intent is now required to receive non-empty values for the `content` and `matched_content` fields in [`AUTO_MODERATION_ACTION_EXECUTION`](/developers/events/gateway-events#auto-moderation-action-execution) gateway events. This matches the intended behavior for message content across the API. ## Updated Connection Property Field Names The `$` prefix in [identify connection properties](/developers/events/gateway-events#identify-identify-connection-properties) are deprecated. The new field names are `os`, `browser`, and `device`. When passed, the `$`-prefixed names will resolve to the new ones. In API v11, support for the previous field names (`$os`, `$browser`, and `$device`) will be removed. ## Auto Moderation Add new [Auto Moderation feature](/developers/resources/auto-moderation) which enables guilds to moderate message content based on keywords, harmful links, and unwanted spam. This change includes: * New endpoints for [creating](/developers/resources/auto-moderation#create-auto-moderation-rule), [updating](/developers/resources/auto-moderation#modify-auto-moderation-rule), and [deleting](/developers/resources/auto-moderation#delete-auto-moderation-rule) Auto Moderation rules * New gateway events emitted when Auto Moderation rules are [created](/developers/events/gateway-events#auto-moderation-rule-create) (`AUTO_MODERATION_RULE_CREATE`), [updated](/developers/events/gateway-events#auto-moderation-rule-update) (`AUTO_MODERATION_RULE_UPDATE `), and [deleted](/developers/events/gateway-events#auto-moderation-rule-delete) (`AUTO_MODERATION_RULE_DELETE `). Requires the `AUTO_MODERATION_CONFIGURATION` (`1 << 20`) intent * New gateway event emitted when an [action is executed](/developers/events/gateway-events#auto-moderation-action-execution) (`AUTO_MODERATION_ACTION_EXECUTION`). Requires the `AUTO_MODERATION_EXECUTION` (`1 << 21`) intent * New [audit log entries](/developers/resources/audit-log#audit-log-entry-object-audit-log-events) when rules are created (`AUTO_MODERATION_RULE_CREATE`), updated (`AUTO_MODERATION_RULE_UPDATE`), or deleted (`AUTO_MODERATION_RULE_DELETE`), or when Auto Moderation performs an action (`AUTO_MODERATION_BLOCK_MESSAGE`) ## Updated Command Permissions Application command permissions have been updated to add more granular control and access to commands in Discord. You can read the major changes below, and [the updated documentation](/developers/interactions/application-commands#permissions) for details. #### Breaking changes * Bearer tokens are now required to edit command permissions. Bearer tokens are tokens tied to an authenticating user's permissions, and can be [retrieved using OAuth](/developers/topics/oauth2). The user must have permission to manage the guild and roles. * [`applications.commands.permissions.update`](/developers/topics/oauth2#shared-resources-oauth2-scopes) scope was added as a requirement to edit command permissions. * Disabled the batch editing endpoint ([`PUT /applications/{application.id}/guilds/{guild.id}/commands/permissions`](/developers/interactions/application-commands#batch-edit-application-command-permissions)). #### Other changes * Created a [`CHANNEL` command permission type](/developers/interactions/application-commands#application-command-permissions-object-application-command-permission-type) * Increase permission limit from `10` to `100` * [constant (`guild_id - 1`)](/developers/interactions/application-commands#application-command-permissions-object-application-command-permissions-constants) to represent all channels in command permissions * Added `default_member_permissions` field, which is a bitwise OR-ed set of [permissions](/developers/topics/permissions#permissions-bitwise-permission-flags), expressed as a string. This replaces the `default_permission` field, which will soon be deprecated. * Added `dm_permission`, which is a boolean flag used to indicate whether a command is available in DMs (only for global application commands). If no value is passed, the global command will be visible in DMs. * Added `APPLICATION_COMMAND_PERMISSIONS_UPDATE` [gateway](/developers/events/gateway-events#application-command-permissions-update) event and `APPLICATION_COMMAND_PERMISSION_UPDATE` [audit log](/developers/resources/audit-log) event. ## Forum Channels Added new channel type, `GUILD_FORUM` (15). A `GUILD_FORUM` channel is an unreleased feature that is very similar (from an API perspective) to a `GUILD_TEXT` channel, except only threads can be created in that channel; messages cannot be sent directly in that channel. Check out the [forums topic](/developers/topics/threads#forums) for more information. ## Guild Bans Pagination The `GET /guilds/{guild.id}/bans` endpoint has been migrated to require pagination to improve reliability and stability. Check out the [endpoint docs](/developers/resources/guild#get-guild-bans) for more information. ## API v10 * API v8 is now deprecated. * `GET /channels/{channel.id}/threads/active` is decommissioned in favor of [`GET /guilds/{guild.id}/threads/active`](/developers/resources/guild#list-active-guild-threads). * Starting in v10, you must specify the message content intent (`1 << 15`) to receive content-related fields in message dispatches. Read more in the [Gateway Intents documentation](/developers/events/gateway#gateway-intents). * To specify a reason for an administrative action in audit logs, apps must now pass the `X-Audit-Log-Reason` header rather than the `reason` parameter for all endpoints. Read more in the [Audit Logs documentation](/developers/resources/audit-log). * Message routes (like [`POST /channels/{channel.id}/messages`](/developers/resources/message#create-message)) now use the `embeds` field (an array of embed objects) instead of `embed`. * The `summary` field for [applications](/developers/resources/application) now returns an empty string for all API versions. * The `name` and `description` fields for [Achievements](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Achievements.md#achievement-struct) are now strings, and localization info is now passed in new `name_localizations` and `description_localizations` dictionaries. This change standardizes localization to match [Application Commands](/developers/interactions/application-commands#localization). Read details in the [Achievements documentation](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Achievements.md#achievement-struct). * Existing attachments must be specified when [`PATCH`ing messages with new attachments](/developers/reference#editing-message-attachments). Any attachments not specified will be removed and replaced with the specified list * Requests to v10 and higher will no longer be supported on `discordapp.com` (this does **not** affect `cdn.discordapp.com`) #### Upcoming changes * API v6 and v7 will be decommissioned **in early 2023** * `MESSAGE_CONTENT` is becoming a privileged intent for verified bots in 75+ servers **on August 31, 2022**. Read details in [the FAQ](https://support-dev.discord.com/hc/en-us/articles/4404772028055-Message-Content-Privileged-Intent-FAQ) or follow [the guide](/developers/tutorials/upgrading-to-application-commands) on updating your app. * The `summary` field for applications will be removed in the next API version (v11) ## Interaction Modals and Application Command Attachment Option Type Interaction modals are now available, allowing applications to prompt users for further detailed input. Check out [the modal docs](/developers/interactions/receiving-and-responding#interaction-response-object-modal) for more information. Application Commands can now add an attachment option type. See [the option type table](/developers/interactions/application-commands#application-command-object-application-command-option-type) for more information. ## Guild Member Timeouts Add new documentation for the recently released guild member timeout feature. ## Guild Scheduled Events * Add official support for `guild_scheduled_events` field on `Guild` resource sent with `GUILD_CREATE` event #### Nov 18, 2021 * Breaking change for return type for `GET /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id}/users` * Add `with_user_count` query param for `GET /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id}` * Return additional `creator` field by default in response for `GET /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id}` * More details and clarification for the guild scheduled events feature. * Document support for `before` and `after` query params for `GET /guilds/{guild.id}/scheduled-events/{guild_scheduled_event.id}/users` #### Nov 15, 2021 Add new documentation for the recently released Guild Scheduled Events feature. ## Application Command Autocomplete Interactions Autocomplete interactions are now available, allowing application commands to provide server completed options. Check out [the autocomplete interaction docs](/developers/interactions/application-commands#autocomplete) for more information. ## Updated Thread Permissions Thread permissions have been updated and simplified: * "Use Public Threads" is now "Create Public Threads", which allows users to create public threads and announcement threads in a channel, even if they cannot send messages in that channel. * "Use Private Threads" is now "Create Private Threads", which allows users to create private threads in a channel, even if they cannot send messages in that channel. A new permission has also been added: * "Send Messages in Threads", which allows users to send a message in a thread. The "Send Messages" permission has no effect in threads: users **must** have "Send Messages in Threads" to send a message in a thread. This allows for setups where a user can participate in a thread but cannot send a message in the parent channel (like a thread on an announcement post). ## User and Message Commands [User commands](/developers/interactions/application-commands#user-commands) and [message commands](/developers/interactions/application-commands#message-commands) are now live! These commands appear on context menus for users and messages, with more to come in the future. Context menu commands are a type of application command. The "Slash Commands" documentation page has been renamed to "Application Commands" and split out by type to show this. ## Select Menu Components Select Menus are now part of the components API! They're the greatest thing since the invention of buttons yesterday. Select menus allow you to offer users a choice of one or many options in a friendly UI-based way. Select menus can be used like other [message components](/developers/components/overview). Learn all the specifics in the [documentation](/developers/components/reference#string-select). ## Support for Multiple Embeds in Message Routes Message routes now accept an embeds array in addition to the existing embed field. Bots can now send up to 10 embeds per message, to be consistent with webhook behavior. The existing embed field is considered deprecated and will be removed in the next API version. ## Buttons and Message Components Message components are now available with our first two components: a layout-based `ActionRow` and...buttons! You can now include buttons on messages sent by your app, whether they're bot messages or responses to interactions. [Learn more about message components](/developers/components/overview). The addition of message components means new fields and response types: * An optional `components` field has been added to the [message object](/developers/resources/message#message-object) * New response types `6` and `7` have been added for [interaction responses](/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type), valid only for component-based interactions ## API v9 API v9 is now available. API v9 includes support for [threads](/developers/topics/threads), an upcoming feature. Older API versions will not receive any Gateway Events for threads, so it is important to update soon! We've prepared a [migration guide](/developers/topics/threads) to help make the upgrade process very straightforward. This documentation is being published early so bots can have at least two months to upgrade before threads launch. Additionally, API v9 also removes the `/channels/:id/messages/:id/suppress-embeds` route. ## Application Command Permissions Need to keep some of your commands safe from prying eyes, or only available to the right people? Commands now support [command permissions](/developers/interactions/application-commands#permissions)! You can enable or disable a command (guild or global) for a specific user or role in a guild. For now, users will still be able to see the commands, but won't be able to use them. New routes have been added to support this functionality: * [`GET Guild Application Command Permissions`](/developers/interactions/application-commands#get-guild-application-command-permissions) * [`GET Application Command Permissions`](/developers/interactions/application-commands#get-application-command-permissions) * [`PUT Application Command Permissions`](/developers/interactions/application-commands#batch-edit-application-command-permissions) A `default_permission` field has also been added to the [ApplicationCommand](/developers/interactions/application-commands#application-command-object-application-command-structure) model. This field allows you to disable commands for everyone in a guild by default, if you prefer to make some of your commands an opt-in experience. ## Large Bot Sharding Lowered to 150,000 Guilds There have been reports that sessions have higher frequency of errors when starting if a bot has joined too many guilds (the gateway connection times out). To account for this we have lowered the requirement for large bot sharding down to 150,000 guilds in order to improve reliability. ## Changes to Slash Command Response Types and Flags Changes to interaction response types have been made to support better designs for application commands: * Type `2` `Acknowledge` has been deprecated * Type `3` `ChannelMessage` has been deprecated * Type `5` `AcknowledgeWithSource` has been renamed to `DeferredChannelMessageWithSource` These deprecated types will be removed and break on **April 9, 2021**. Additionally, `flags` has been documented on [InteractionApplicationCommandCallbackData](/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-data-structure). Setting `flags` to `64` will make the interaction response ephemeral. ## Slash Commands in DMs Slash Commands are now supported in DMs with bots. Due to this change, some of the fields on the [Interaction object](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) have been made optional. Newly optional fields don't reflect any behavior changes in Slash Commands within guilds; they are to support commands in the context of a DM only. ## Change to Permission Checking when Creating Channels Permission overwrites in the guild channel creation endpoint are now validated against the permissions your bot has in the guild. Permission overwrites specified in the request body when creating guild channels will now require your bot to also have the permissions being applied. Setting `MANAGE_ROLES` permission in channel overwrites is only possible for guild administrators or users with `MANAGE_ROLES` as a permission overwrite in the channel. ## Slash Commands and Interactions Slash Commands are here! There's a *lot* to cover, so go check out specific documentation under [Slash Commands](/developers/interactions/application-commands). Slash Commands include some new features for webhooks as well: * Webhooks can now update previously-sent messages from the same webhook using [Edit Webhook Message](/developers/resources/webhook#edit-webhook-message) and [Delete Webhook Message](/developers/resources/webhook#delete-webhook-message) This PR also documents the `application` field on the `READY` gateway event, which is a partial [application object](/developers/resources/application#application-object) containing `id` and `flags`. ## Inline Replies Inline Replies have been added to our documentation. They behave differently in v6 and v8, so be cautious in your implementation: * Inline replies are type `19` in v8, but remain type `0` in v6 * You can now add a `message_reference` on message create to create a reply * A new field `referenced_message` has been added to the [Message Object](/developers/resources/message#message-object) * A new field `replied_user` has been added to the [Allowed Mentions Object](/developers/resources/message#allowed-mentions-object) * [Message Create](/developers/events/gateway-events#message-create) gateway event is guaranteed to have a `referenced_message` if the message created is a reply. Otherwise, that field is not guaranteed. ## Stickers Stickers are now documented as part of the [message](/developers/resources/message#message-object) object. ## Gateway v6 Intent Restrictions The v6 gateway now applies the restrictions for gateway intents. This means the new chunking limitations are now in effect, regardless of intents being used. See [Request Guild Members](/developers/events/gateway-events#request-guild-members) for further details. Additionally, if privileged intents are not enabled in the application dashboard the bot will not receive the events for those intents. All other intents are always enabled by default unless specified otherwise by the identify payload. We have made a support article to explain some of the changes and resulting issues with more details: [Gateway Update FAQ](https://dis.gd/gwupdate) ## API and Gateway V8 We've introduced API and Gateway v8! Changes are noted throughout the documentation, and you can also read [this commit in our docs repo](https://github.com/discord/discord-api-docs/commit/545ff4a7883e5eee7ee91d19a5e5d760a0730033) for a full diff. The changes are: * API and Gateway v8 are now available. v6 is still the default for the time being. * [Gateway Intents](/developers/events/gateway#gateway-intents) are now required * Removed `guild_subscriptions` in identify in favor of [Gateway Intents](/developers/events/gateway#gateway-intents). * All permissions have been converted to strings-serialized numbers. As such, `permissions_new`, `allow_new`, and `deny_new` have been removed * The `game` field has been removed. If you need a direct replacement, you can instead reference the first element of `activities` * Channel Permission Overwrite `type`s are now numbers (0 and 1) instead of strings ("role" and "member"). However due to a current technical constraint, they are string-serialized numbers in audit log `options`. * `embed_enabled` and `embed_channel_id` have been removed. Use `widget_enabled` and `widget_channel_id` instead. * Form body errors have been improved to include more helpful messaging on validation. [See more here](/developers/reference#error-messages) * The `Retry-After` header value and `retry_after` body value is now based in seconds instead of milliseconds (e.g. `123` means 123 seconds) * The `X-RateLimit-Precision` header is no longer respected. `X-RateLimit-Reset` and `X-RateLimit-Reset-After` are always returned at millisecond precision (e.g. `123.456` instead of `124`) * Bots no longer receive [Channel Create Gateway Event](/developers/events/gateway-events#channel-create) for DMs * `delete-message-days` is no longer available. Use `delete_message_days`. * Removed `roles`, `premium_since`, and `nick` from [Presence Update Gateway Event](/developers/events/gateway-events#presence-update) * Removed some [integration object](/developers/resources/guild#integration-object) fields for Discord application integrations * Removed `include_applications` from [Get Guild Integrations](/developers/resources/guild#get-guild-integrations). Application integrations are always included. * The following deprecated routes have been removed for better naming conventions: Removed in favor of `/guilds//widget`: * `/guilds//embed` Removed in favor of `/guilds//widget.json`: * `/servers//embed.json` * `/servers//widget.json` * `/guilds//embed.json` Removed in favor of `/guilds//widget.png`: * `/guilds//embed.png` Removed in favor of `/channels//messages/bulk-delete`: * `/channels//messages/bulk_delete/` Removed in favor of `/invites//`: * `/invite//` ## New Permission Fields Documented `permissions_new`, `allow_new`, and `deny_new` as string-serialized permission bitfields. ## Legacy Mention Behavior Deprecation The legacy mention behavior for bots is now removed, and granular control of mentions should use the [Allowed Mentions](/developers/resources/message#allowed-mentions-object) API moving forwards. ## New Properties on Guild Members Chunk Event The [Guild Members Chunk](/developers/events/gateway-events#guild-members-chunk) gateway event now contains two properties: `chunk_index` and `chunk_count`. These values can be used to keep track of how many events you have left to receive in response to a [Request Guild Members](/developers/events/gateway-events#request-guild-members) command. ## New Allowed Mentions Object We've added a way to specify mentions in a more granular form. This change also begins the start of a 60 day deprecation cycle on legacy mention behavior. Read more: * [Allowed mentions object](/developers/resources/message#allowed-mentions-object) ## New Invite Events and Reactions Endpoint We've added a new endpoint for deleting all reactions of a specific emoji from a message, as well as some new invite and reaction gateway events. Read more: * [Delete All Reactions for Emoji](/developers/resources/message#delete-all-reactions-for-emoji) * [Invite Create](/developers/events/gateway-events#invite-create) * [Invite Delete](/developers/events/gateway-events#invite-delete) * [Message Reaction Remove Emoji](/developers/events/gateway-events#message-reaction-remove-emoji) ## Rich Presence Spectate Approval The [Spectate](/developers/developer-tools/game-sdk#onactivityspectate) functionality of Rich Presence no longer requires whitelisting or approval. ## Gateway Intents We've added documentation around a brand new feature: [Gateway Intents!](/developers/events/gateway#gateway-intents) Gateway Intents are a great way to specify which events you want to receive from our gateway. Go on, save yourself some bandwidth and CPU usage. Using Intents will change the behavior of some existing events and commands, so please refer to: * [Guild Create](/developers/events/gateway-events#guild-create) * [Request Guild Members](/developers/events/gateway-events#request-guild-members) * [Guild Member Add](/developers/events/gateway-events#guild-member-add) * [Guild Member Remove](/developers/events/gateway-events#guild-member-remove) * [Guild Member Update](/developers/events/gateway-events#guild-member-update) * [Presence Update](/developers/events/gateway-events#presence-update) * [List Guild Members](/developers/resources/guild#list-guild-members) ## IP Discovery Updates Updated our [IP discovery message](/developers/topics/voice-connections#ip-discovery). The old message is deprecated and will be removed in the future. ## GameSDK Version 2.5.6 Fixed a bug from the 2.5.5 release that caused network handshakes to fail, resulting in no networking data being sent. The networking manager and integrated lobby networking should be full operational again after updating. ## GameSDK Version 2.5.5 We've shipped some updates to the GameSDK, including support for Linux as well as the IL2CPP backend system for Unity. These changes also fixed a bug in the [`SetUserAchievement()`](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Achievements.md#setuserachievement) method. Get the latest at the top of the [Getting Started](/developers/developer-tools/game-sdk#step-1-get-the-sdk) documentation. If you're looking for help interacting with the GameSDK or want to report a bug, join us on the [official Discord](https://discord.gg/discord-developers). ## Changes to Special Channels News Channels are now changed to Announcement Channels. Developer License owners will continue to get access to them (both existing and new). Underlying channel type (GUILD\_NEWS = 5) remains the same. ## More Precise Rate Limits You can now get more precise rate limit reset times, via a new request header. Check out the [rate limits](/developers/topics/rate-limits) documentation for more information. ## Bot Tokens for Achievements You can now use Bot tokens for authorization headers against the HTTP API for [Achievements](https://github.com/discord/discord-api-docs/blob/legacy-gamesdk/docs/game_sdk/Achievements.md#the-api-way). ## Additional Team Information Additional information around Teams has been added to both the API and the documentation. The [Teams](/developers/topics/teams) page now includes information about the team and team member objects. Additionally, the [Get Current Application Information](/developers/topics/oauth2#get-current-bot-application-information) endpoint now returns a `team` object if that application belongs to a team. That documentation has also been updated to includes fields that were missing for applications that are games sold on Discord. ## Added Info Around Nitro Boosting Experiment Additional information has been documented to support [Server Nitro Boosting](https://support.discord.com/hc/en-us/articles/360028038352-Server-Boosting). This includes the addition of a few [message types](/developers/resources/message#message-object-message-types), as well as some [new fields on guilds](/developers/resources/guild#guild-object-premium-tier). Please note that this feature is currently under experimentation, and these fields may be subject to change. ## Deprecation of Discord-RPC Rich Presence SDK The [Discord-RPC](https://github.com/discord/discord-rpc) implementation of Rich Presence has been deprecated in favor of Discord's new GameSDK. If you're interested in using Rich Presence, please read our [SDK Starter Guide](/developers/developer-tools/game-sdk#getting-started) and check out the relevant functions in the [Activity Manager](/developers/developer-tools/game-sdk#activities). ## New Invite Object Fields The [Invite Object](/developers/resources/invite#invite-object) now includes two additional fields, `target_user` and `target_user_type`. ## Ask to Join & Rich Presence SDK Ask to Join no longer requires approval or whitelisting to use. You are welcome to create in-game UI, but all Ask to Join requests are also now handled by the Discord overlay. There have also been some small additions to the Rich Presence SDK. The previously undocumented `UpdateHandlers()` function is now documented. ## Documentation: Dispatch Store Listings Dispatch documentation around store listings has been removed. Store pages for the Discord Store are now managed entirely within the [Developer Portal](https://discord.com/developers). ## Enhancement: User Object The [User object](/developers/resources/user#user-object) now includes two new additional fields, `premium_type` and `flags`. These can be used to know the Nitro status of a user, or determine which HypeSquad house a user is in. ## Documentation Fix: List of Open DMS in Certain Payloads The documentation has been updated to correctly note that the `private_channels` field in the [Ready](/developers/events/gateway-events#ready) should be an empty array, as well as the response from `/users/@me/channels` for a bot user. This change has been in effect for a long time, but the documentation was not updated. ## Deprecation: RPC online member count and members list We released server changes that allow guilds to represent an incomplete state of the member list in our clients, which results in inaccurate member lists and online counts over RPC. These fields are now deprecated and will now return an empty members array and an online count of 0 moving forward. ## Enhancement: New Message Properties Additional `activity` and `application` fields—as well as corresponding object documentation—have been added to the [Message](/developers/resources/message#message-object) object in support of our newly-released [Spotify integration](https://support.discord.com/hc/en-us/articles/360000167212-Discord-Spotify-Connection) and previous Rich Presence enhancements. ## Enhancement: Get Guild Emoji Endpoint The [Get Guild Emoji](/developers/resources/emoji#get-guild-emoji) response now also includes a user object if the emoji was added by a user. ## Deprecation: Accept Invite Endpoint The [Accept Invite](/developers/resources/invite) endpoint is deprecated starting today, and will be discontinued on March 23, 2018. The [Add Guild Member](/developers/resources/guild#add-guild-member) endpoint should be used in its place. ## Semi-Breaking Change: Very Large Bot Sharding Additional sharding requirements and information for bots in over 100,000 guilds has been added. This requires a small change in numbers of shards for affected bots. See the [documentation](/developers/events/gateway#sharding-for-large-bots) for more information. ## New Feature: Rich Presence Rich Presence is now live and available for all developers! Rich Presence allows developers to closely integrate with Discord in a number of new, cool ways like: * Showing more information about a user's current game in their profile * Allowing users to post invitations to join their party or spectate their game in chat * Displaying "Spectate" and "Ask to Join" buttons on users' profiles For more information, check out our [Rich Presence site](https://discord.com/rich-presence). To get started on development, [read the docs](/developers/rich-presence/overview)! ## Breaking Change: API & Gateway Below v6 Discontinued [API](/developers/reference#api-versioning) and Gateway versions below v6 are now discontinued after being previously deprecated. Version 6 is now the default API and Gateway version. Attempting to use a version below 6 will result in an error. ## New Feature: Channel Categories Changes have been made throughout the documentation to reflect the addition of channel categories to Discord. These includes an additional field—`parent_id`—to the base [channel](/developers/resources/channel#channel-object) object and a new [channel category example](/developers/resources/channel#channel-object-example-channel-category). ## New Feature: Emoji Endpoints [Emoji endpoints](/developers/resources/emoji) have been added to the API. Bots can now manage guild emojis to their robo-hearts' content! ## Breaking Change: Presence Activity Objects The `type` field in the [activity object](/developers/events/gateway-events#activity-object) for [Gateway Status Update](/developers/events/gateway-events#update-presence) and [Presence Update](/developers/events/gateway-events#presence-update) payloads is no longer optional when the activity object is not null. ## Breaking Change: Default Channels After today, we are changing how default channels function. The "default" channel for a given user is now the channel with the highest position that their permissions allow them to see. New guilds will no longer have a default channel with the same id as the guild. Existing guilds will not have their #general channel id changed. It is possible, if permissions are set in such a way, that a user will not have a default channel in a guild. We saw a use case in many servers where the previously-default #general channel was being repurposed as an announcement-only, non-writable channel for new members by using bots to clear the entire message history. Now, that channel can simply be deleted and re-created with the desired permissions. This change also allows dynamic default channels for users based on permissions. We are also rolling out a change in conjunction that will allow Discord to remember your last-visited channel in a guild across sessions. Newly-joined users will be directed to the guild's default channel on first join; existing members will return to whichever channel they last visited. ## New Feature: Audit Logs Audit logs are here! Well, they've been here all along, but now we've got [documentation](/developers/resources/audit-log) about them. Check it out, but remember: with great power comes great responsibility. ## Breaking Change: Version 6 * [Channel](/developers/resources/channel#channel-object) Object * `is_private` removed * [`type`](/developers/resources/channel#channel-object-channel-types) is now an integer * `recipient` is now `recipients`, an array of [user](/developers/resources/user#user-object) objects * [Message](/developers/resources/message#message-object) Object * [`type`](/developers/resources/message#message-object-message-types) added to support system messages * [Status Update](/developers/events/gateway-events#update-presence-gateway-presence-update-structure) Object * `idle_since` renamed to `since` [`Activity::AddButton`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Activity.html#aab07650fcff18565eb78a1e2df46627e [`ActivityInvite`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1ActivityInvite.html#af980f140c1459e1cd8f6ef3f3c07547c [`Call::GetPTTReleaseDelay`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Call.html#ab8dc6b1527728fecb17f266d5b3e9e6e [`Call::SetPTTActive`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Call.html#ac442b1d69b9256abbb188583c0c81c41 [`Client`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a91716140c699d8ef0bdf6bfd7ee0ae13 [`Client::AddLogCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#af78996cff24a40f5dc7066beed16692c [`Client::CreateOrJoinLobbyWithMetadata`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a5c84fa76c73cf3c0bfd68794ca5595c1 [`Client::ExchangeChildToken`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a59f5d9d14f79eb318bf4d57f4e87a5c1 [`Client::GetCurrentUser`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a7edea2a3dfe9ae560d5fa5ba8663b5cc [`Client::GetCurrentUserV2`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ae52259570ba657252d91f5580636fe5d [`Client::GetGuildChannels`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#adba1e5a83c219a9c4f6dab1657778017 [`Client::GetLobbyMessagesWithLimit`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a0586192e85caf548b8b321f1cb21301f [`Client::GetRelationships`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ad481849835cd570f0e03adafcf90125d [`Client::GetRelationshipsByGroup`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a9f7898d3f3d1ec92b06c662df70746d5 [`Client::GetUserGuilds`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#aac1ec02df6074ed9213ce230e6a42fe1 [`Client::GetUserMessageSummaries`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a32dafc20ff1f99b019e40bdc81f46dde [`Client::GetUserMessagesWithLimit`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a054a758a76c5873b38a4d79651a5f26c [`Client::JoinLinkedLobbyGuild`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a54ec764e72e168de419ac14e24e8fc60 [`Client::OpenConnectedGamesSettingsInDiscord`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a24f268f5eebe9919a3f774354eb577e0 [`Client::RegisterAuthorizeRequestCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a5f34b873e127a446c9ab549e4588ccd7 [`Client::RegisterLaunchCommand`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a024d7222931fdcb7d09c2b107642ecab [`Client::RegisterLaunchSteamApplication`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a45b2c791c5b06f77d457dacb53dfba40 [`Client::RemoveAuthorizeRequestCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ab7e48864b0cedf3e8572a228ca401f2a [`Client::RemoveDiscordAndGameFriend`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#aa6d393a3d98ec5d06faef49a57d1a89b [`Client::RevokeToken`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a30ccea6366efaf0b884efcdcc28a6f2d [`Client::SetActivityInviteCreatedCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a3b4e37a222a8662506d763514774bedc [`Client::SetAecDump`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a3a05b2cafaa546d915a5249c63f4059f [`Client::SetEngineManagedAudioSession`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ade08897214152b9acfa79c263e77e366 [`Client::SetHttpRequestTimeout`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ae5fe2518b0b1b05ee1745ab0a79096b9 [`Client::SetRelationshipGroupsUpdatedCallback`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#af12441ef091298f968075b7190851098 [`Client::SetSpeakerMode`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ac269ab57407e3b83e2bb2d30895e666d [`Client::SetVoiceLogDir`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a48c6b7e8bbc2b632a935acafc6a5f7a7 [`Client::StartCallWithAudioCallbacks`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#abcaa891769f9e912bfa0e06ff7221b05 [`Client::UnmergeIntoProvisionalAccount`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a2da21ae8a3015e0e5e42c1a7226b256f [`Client::UpdateRichPresence`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#af0a85e30f2b3d8a0b502fd23744ee58e [`Client::UpdateToken`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a606b32cef7796f7fb91c2497bc31afc4 [`ClientCreateOptions`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1ClientCreateOptions.html#ae655ad66ba64f443496c158307cc77b4 [`GuildChannel`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1GuildChannel.html#ac83eedfa1d9434dfa245ae39bb3a0915 [`MessageHandle`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1MessageHandle.html#ae25595b43bc74b0c4c92c5165d16382f [`MessageHandle::ModerationMetadata`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1MessageHandle.html#afb9ae126f6b1f0de006f2be8e3688205 [`RelationshipHandle`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1RelationshipHandle.html#a7da36b15ad0b7d38ba658a622e9ded77 # Components Overview Source: https://docs.discord.com/developers/components/overview Learn about Discord's interactive message components. Components allow you to add interactive elements to modals and the messages your app sends. They're accessible, customizable, and easy to use. For an introduction to component types and modals, see the [Components & Modals](/developers/platform/components) platform page. Image showing examples of components UI To use components, messages must be sent with the `IS_COMPONENTS_V2` flag (`1<<15`). Note that using this flag disables traditional content and embeds - all content must be sent as components instead. [Legacy message component behavior](/developers/components/reference#legacy-message-component-behavior) will **not** be deprecated and will continue to be available to your apps on a message-by-message basis. However, we recommend using the new components for new projects and features. }> A guide on sending Message Components with examples. }> A guide on sending Modal Components with examples. }> Explore the Components reference documentation. *** ## Get Help & Join the Community Do you have a question or want to connect with other app developers? * Join our [DDevs Discord Server](https://discord.gg/discord-developers) and get help from the community, share best practices, and discover new ways to enhance your apps. # Component Reference Source: https://docs.discord.com/developers/components/reference This document serves as a comprehensive reference for all available components. It covers three main categories: * **Layout Components** - For organizing and structuring content (Action Rows, Sections, Containers) * **Content Components** - For displaying static text, images, and files (Text Display, Media Gallery, Thumbnails) * **Interactive Components** - For user interactions (Buttons, Select Menus, Text Input) To use these components, you need to send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2) which can be sent on a per-message basis. Once a message has been sent with this flag, it can't be removed from that message. This enables the new components system with the following changes: * The `content` and `embeds` fields will no longer work but you'll be able to use [Text Display](/developers/components/reference#text-display) and [Container](/developers/components/reference#container) as replacements * Attachments won't show by default - they must be exposed through components * The `poll` and `stickers` fields are disabled * Messages allow up to 40 total components [Legacy component behavior](/developers/components/reference#legacy-message-component-behavior) will continue to work but provide less flexibility and control over the message layout. For a practical guide on implementing these components, see our [Using Message Components](/developers/components/using-message-components) and [Using Modal Components](/developers/components/using-modal-components) documentation. *** ## What is a Component Components allow you to style and structure your messages, modals, and interactions. They are interactive elements that can create rich user experiences in your Discord applications. Components are a field on the [message object](/developers/resources/message#message-object) and [modal](/developers/interactions/receiving-and-responding#interaction-response-object-modal). You can use them when creating messages or responding to an interaction, like an [application command](/developers/interactions/application-commands). ### Component Object ###### Component Types The following is a complete table of available components. Details about each component are in the sections below. | Type | Name | Description | Style | Usage | | ---- | ------------------------------------------------------------------------- | -------------------------------------------------------------- | ----------- | -------------- | | 1 | [Action Row](/developers/components/reference#action-row) | Container to display a row of interactive components | Layout | Message | | 2 | [Button](/developers/components/reference#button) | Button object | Interactive | Message | | 3 | [String Select](/developers/components/reference#string-select) | Select menu for picking from defined text options | Interactive | Message, Modal | | 4 | [Text Input](/developers/components/reference#text-input) | Text input object | Interactive | Modal | | 5 | [User Select](/developers/components/reference#user-select) | Select menu for users | Interactive | Message, Modal | | 6 | [Role Select](/developers/components/reference#role-select) | Select menu for roles | Interactive | Message, Modal | | 7 | [Mentionable Select](/developers/components/reference#mentionable-select) | Select menu for mentionables (users *and* roles) | Interactive | Message, Modal | | 8 | [Channel Select](/developers/components/reference#channel-select) | Select menu for channels | Interactive | Message, Modal | | 9 | [Section](/developers/components/reference#section) | Container to display text alongside an accessory component | Layout | Message | | 10 | [Text Display](/developers/components/reference#text-display) | Markdown text | Content | Message, Modal | | 11 | [Thumbnail](/developers/components/reference#thumbnail) | Small image that can be used as an accessory | Content | Message | | 12 | [Media Gallery](/developers/components/reference#media-gallery) | Display images and other media | Content | Message | | 13 | [File](/developers/components/reference#file) | Displays an attached file | Content | Message | | 14 | [Separator](/developers/components/reference#separator) | Component to add vertical padding between other components | Layout | Message | | 17 | [Container](/developers/components/reference#container) | Container that visually groups a set of components | Layout | Message | | 18 | [Label](/developers/components/reference#label) | Container associating a label and description with a component | Layout | Modal | | 19 | [File Upload](/developers/components/reference#file-upload) | Component for uploading files | Interactive | Modal | | 21 | [Radio Group](/developers/components/reference#radio-group) | Single-choice set of options | Interactive | Modal | | 22 | [Checkbox Group](/developers/components/reference#checkbox-group) | Multi-selectable group of checkboxes | Interactive | Modal | | 23 | [Checkbox](/developers/components/reference#checkbox) | Single checkbox for yes/no choice | Interactive | Modal | *** ## Anatomy of a Component All components have the following fields: | Field | Type | Description | | ----- | ------- | ---------------------------------------------------------------------------------------------- | | type | integer | The [type](/developers/components/reference#component-object-component-types) of the component | | id? | integer | 32 bit integer used as an optional identifier for component | The `id` field is optional and is used to identify components in the response from an interaction. The `id` must be unique within the message and is generated sequentially if left empty. Generation of `id`s won't use another `id` that exists in the message if you have one defined for another component. Sending components with an `id` of `0` is allowed but will be treated as empty and replaced by the API. ###### Custom ID Additionally, interactive components like buttons and selects must have a `custom_id` field. The developer defines this field when sending the component payload, and it is returned in the interaction payload sent when a user interacts with the component. For example, if you set `custom_id: click_me` on a button, you'll receive an interaction containing `custom_id: click_me` when a user clicks that button. `custom_id` is only available on interactive components and must be unique per component. Multiple components on the same message must not share the same `custom_id`. This field is a string of 1 to 100 characters and can be used flexibly to maintain state or pass through other important data. | Field | Type | Description | | ---------- | ------ | ---------------------------------------------- | | custom\_id | string | Developer-defined identifier, 1-100 characters | *** ## Action Row An Action Row is a top-level layout component. Action Rows can contain one of the following: * Up to 5 contextually grouped [buttons](/developers/components/reference#button) * A single select component ([string select](/developers/components/reference#string-select), [user select](/developers/components/reference#user-select), [role select](/developers/components/reference#role-select), [mentionable select](/developers/components/reference#mentionable-select), or [channel select](/developers/components/reference#channel-select)) [Label](/developers/components/reference#label) is recommended for use over an Action Row in modals. Action Row with Text Inputs in modals are now deprecated. ###### Action Row Structure | Field | Type | Description | | ---------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | integer | `1` for action row component | | id? | integer | Optional identifier for component | | components | array of [action row child components](/developers/components/reference#action-row-action-row-child-components) | Up to 5 interactive [button](/developers/components/reference#button) components or a single [select](/developers/components/reference#user-select) component | ###### Action Row Child Components | Available Components | Description | | ------------------------------------------------------------------------- | ----------------------------------------- | | [Button](/developers/components/reference#button) | An Action Row can contain up to 5 Buttons | | [String Select](/developers/components/reference#string-select) | A single String Select | | [User Select](/developers/components/reference#user-select) | A single User Select | | [Role Select](/developers/components/reference#role-select) | A single Role Select | | [Mentionable Select](/developers/components/reference#mentionable-select) | A single Mentionable Select | | [Channel Select](/developers/components/reference#channel-select) | A single Channel Select | ###### Examples Example of an Action Row with three buttons ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 1, // ComponentType.ACTION_ROW "components": [ { "type": 2, // ComponentType.BUTTON "custom_id": "click_yes", "label": "Accept", "style": 1 }, { "type": 2, // ComponentType.BUTTON "label": "Learn More", "style": 5, "url": "http://watchanimeattheoffice.com/" }, { "type": 2, // ComponentType.BUTTON "custom_id": "click_no", "label": "Decline", "style": 4 } ] } ] } ``` *** ## Button A Button is an interactive component that can only be used in messages. It creates clickable elements that users can interact with, sending an [interaction](/developers/interactions/receiving-and-responding#interaction-object) to your app when clicked. Buttons must be placed inside an [Action Row](/developers/components/reference#action-row) or a [Section](/developers/components/reference#section)'s `accessory` field. ###### Button Structure | Field | Type | Description | | ----------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | type | integer | `2` for a button | | id? | integer | Optional identifier for component | | style | integer | A [button style](/developers/components/reference#button-button-styles) | | label? | string | Text that appears on the button; max 80 characters | | emoji? | partial [emoji](/developers/resources/emoji#emoji-object) | `name`, `id`, and `animated` | | custom\_id? | string | Developer-defined identifier for the button; 1-100 characters | | sku\_id? | snowflake | Identifier for a purchasable [SKU](/developers/resources/sku#sku-object), only available when using premium-style buttons | | url? | string | URL for link-style buttons; max 512 characters | | disabled? | boolean | Whether the button is disabled (defaults to `false`) | Buttons come in various styles to convey different types of actions. These styles also define what fields are valid for a button. * Non-link and non-premium buttons **must** have a `custom_id`, and cannot have a `url` or a `sku_id`. * Link buttons **must** have a `url`, and cannot have a `custom_id` * Link buttons do not send an [interaction](/developers/interactions/receiving-and-responding#interaction-object) to your app when clicked * Premium buttons **must** contain a `sku_id`, and cannot have a `custom_id`, `label`, `url`, or `emoji`. * Premium buttons do not send an [interaction](/developers/interactions/receiving-and-responding#interaction-object) to your app when clicked ###### Button Styles | Name | Value | Action | Required Field | | --------- | ----- | -------------------------------------------------------------- | -------------- | | Primary | 1 | The most important or recommended action in a group of options | `custom_id` | | Secondary | 2 | Alternative or supporting actions | `custom_id` | | Success | 3 | Positive confirmation or completion actions | `custom_id` | | Danger | 4 | An action with irreversible consequences | `custom_id` | | Link | 5 | Navigates to a URL | `url` | | Premium | 6 | Purchase | `sku_id` | ###### Examples ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 1, // ComponentType.ACTION_ROW "components": [ { "type": 2, // ComponentType.BUTTON, "custom_id": "click_me", "label": "Click me!", "style": 1 } ] } ] } ``` When a user interacts with a Button in a message, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 3, // InteractionType.MESSAGE_COMPONENT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "component_type": 2, // ComponentType.BUTTON "id": 2, "custom_id": "click_me", }, } ``` ### Button Design Guidelines ###### General Button Content * 34 characters max with icon or emoji. * 38 characters max without icon or emoji. * Keep text concise and to the point. * Use clear and easily understandable language. Avoid jargon or overly technical terms. * Use verbs that indicate the outcome of the action. * Maintain consistency in language and tone across buttons. * Anticipate the need for translation and test for expansion or contraction in different languages. ###### Multiple Buttons Use different button styles to create a hierarchy. Use only one `Primary` button per group. Example showing one primary button per button group If there are multiple buttons of equal significance, use the `Secondary` button style for all buttons. Example showing multiple buttons in a group with equal significance ###### Premium Buttons Premium buttons will automatically have the following: * Shop Icon * SKU name * SKU price A premium button *** ## String Select A String Select is an interactive component that allows users to select one or more provided `options`. String Selects can be configured for both single-select and multi-select behavior. When a user finishes making their choice(s) your app receives an [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure). String Selects are available in messages and modals. They must be placed inside an [Action Row](/developers/components/reference#action-row) in messages and a [Label](/developers/components/reference#label) in modals. ###### String Select Structure | Field | Type | Description | | --------------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | type | integer | `3` for string select | | id? | integer | Optional identifier for component | | custom\_id | string | ID for the select menu; 1-100 characters | | options | array of [select options](/developers/components/reference#string-select-select-option-structure) | Specified choices in a select menu; max 25 | | placeholder? | string | Placeholder text if nothing is selected or default; max 150 characters | | min\_values?\* | integer | Minimum number of items that must be chosen (defaults to 1); min 0 (see note), max 25 | | max\_values? | integer | Maximum number of items that can be chosen (defaults to 1); max 25 | | required?\*\* | boolean | Whether the string select is required to answer in a modal (defaults to `true`) | | disabled?\*\*\* | boolean | Whether select menu is disabled in a message (defaults to `false`) | \* `min_values` must be either omitted or at least `1` if `required` is omitted or `true`. \*\* The `required` field is only available for String Selects in modals. It is ignored in messages. \*\*\* Using `disabled` in a modal will result in an error. Modals can not currently have disabled components in them. ###### Select Option Structure | Field | Type | Description | | ------------ | ---------------------------------------------------------------- | -------------------------------------------------------- | | label | string | User-facing name of the option; max 100 characters | | value | string | Dev-defined value of the option; max 100 characters | | description? | string | Additional description of the option; max 100 characters | | emoji? | partial [emoji](/developers/resources/emoji#emoji-object) object | `id`, `name`, and `animated` | | default? | boolean | Will show this option as selected by default | ###### String Select Interaction Response Structure | Field | Type | Description | | ----------------- | ---------------- | ------------------------------------------------------------ | | type\* | integer | `3` for a String Select | | component\_type\* | integer | `3` for a String Select | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | values | array of strings | The text of the selected options | \* In message interaction responses `component_type` will be returned and in modal interaction responses `type` will be returned. ###### Examples Example of a String Select with three options ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 1, // ComponentType.ACTION_ROW, "id": 1, "components": [ { "type": 3, // ComponentType.STRING_SELECT "id": 2, "custom_id": "favorite_bug", "placeholder": "Favorite bug?", "options": [ { "label": "Ant", "value": "ant", "description": "(best option)", "emoji": {"name": "🐜"} }, { "label": "Butterfly", "value": "butterfly", "emoji": {"name": "🦋"} }, { "label": "Caterpillar", "value": "caterpillar", "emoji": {"name": "🐛"} } ] } ] } ] } ``` When a user interacts with a StringSelect in a message, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 3, // InteractionType.MESSAGE_COMPONENT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "component_type": 3, // ComponentType.STRING_SELECT "custom_id": "favorite_bug", "values": [ "butterfly", ] }, } ``` Example of a String Select with three options in a modal ```jsonc theme={"system"} { "type": 9, // InteractionCallbackType.MODAL "data": { "custom_id": "bug_modal", "title": "Bug Survey", "components": [ { "type": 18, // ComponentType.LABEL "id": 1, "label": "Favorite bug?", "component": { "type": 3, // ComponentType.STRING_SELECT "id": 2, "custom_id": "favorite_bug", "placeholder": "Ants are the best", "options": [ { "label": "Ant", "value": "ant", "description": "(best option)", "emoji": {"name": "🐜"} }, { "label": "Butterfly", "value": "butterfly", "emoji": {"name": "🦋"} }, { "label": "Caterpillar", "value": "caterpillar", "emoji": {"name": "🐛"} } ] } } ] } } ``` When a user submits a modal that contains a String Select, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "bug_modal", "components": [ { "type": 18, // ComponentType.LABEL "id": 1, "component": { "type": 3, // ComponentType.STRING_SELECT "id": 2, "custom_id": "favorite_bug", "values": [ "butterfly", ] } } ] }, } ``` *** ## Text Input Text Input is an interactive component that allows users to enter free-form text responses in modals. It supports both short, single-line inputs and longer, multi-line paragraph inputs. Text Inputs can only be used within modals and must be placed inside a [Label](/developers/components/reference#label). We no longer recommend using Text Input within an [Action Row](/developers/components/reference#action-row) in modals. Going forward all Text Inputs should be placed inside a [Label](/developers/components/reference#label) component. ###### Text Input Structure | Field | Type | Description | | ------------ | ------- | ------------------------------------------------------------------------------------- | | type | integer | `4` for a text input | | id? | integer | Optional identifier for component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | style | integer | The [Text Input Style](/developers/components/reference#text-input-text-input-styles) | | min\_length? | integer | Minimum input length for a text input; min 0, max 4000 | | max\_length? | integer | Maximum input length for a text input; min 1, max 4000 | | required? | boolean | Whether this component is required to be filled (defaults to `true`) | | value? | string | Pre-filled value for this component; max 4000 characters | | placeholder? | string | Custom placeholder text if the input is empty; max 100 characters | The `label` field on a Text Input is deprecated in favor of `label` and `description` on the [Label](/developers/components/reference#label) component. ###### Text Input Styles | Name | Value | Description | | --------- | ----- | ----------------- | | Short | 1 | Single-line input | | Paragraph | 2 | Multi-line input | ###### Text Input Interaction Response Structure | Field | Type | Description | | ---------- | ------- | ------------------------------------------------------------ | | type | integer | `4` for a Text Input | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | value | string | The user's input text | ###### Examples A modal with Text Input in a Label ```jsonc theme={"system"} { "type": 9, // InteractionCallbackType.MODAL "data": { "custom_id": "game_feedback_modal", "title": "Game Feedback", "components": [ { "type": 18, // ComponentType.LABEL "label": "What did you find interesting about the game?", "description": "Please give us as much detail as possible so we can improve the game!", "component": { "type": 4, // ComponentType.TEXT_INPUT "custom_id": "game_feedback", "style": 2, "min_length": 100, "max_length": 4000, "placeholder": "Write your feedback here...", "required": true } } ] } } ``` When a user submits a modal that contains a TextInput, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "game_feedback_modal", "components": [ { "type": 18, // ComponentType.LABEL "id": 1, "component": { "type": 4, // ComponentType.TEXT_INPUT "id": 2, "custom_id": "game_feedback", "value": "The recent changes to acceleration feel much better, but shadows still need help" } } ] }, } ``` *** ## User Select A User Select is an interactive component that allows users to select one or more users in a message or modal. Options are automatically populated based on the server's available users. User Selects can be configured for both single-select and multi-select behavior. When a user finishes making their choice(s) your app receives an [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure). User Selects are available in messages and modals. They must be placed inside an [Action Row](/developers/components/reference#action-row) in messages and a [Label](/developers/components/reference#label) in modals. ###### User Select Structure | Field | Type | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | integer | `5` for user select | | id? | integer | Optional identifier for component | | custom\_id | string | ID for the select menu; 1-100 characters | | placeholder? | string | Placeholder text if nothing is selected; max 150 characters | | default\_values? | array of [default value objects](/developers/components/reference#user-select-select-default-value-structure) | List of default values for auto-populated select menu components; number of default values must be in the range defined by `min_values` and `max_values` | | min\_values?\* | integer | Minimum number of items that must be chosen (defaults to 1); min 0 (see note), max 25 | | max\_values? | integer | Maximum number of items that can be chosen (defaults to 1); max 25 | | required?\*\* | boolean | Whether the user select is required to answer in a modal (defaults to `true`) | | disabled?\*\*\* | boolean | Whether select menu is disabled in a message (defaults to `false`) | \* `min_values` must be either omitted or at least `1` if `required` is omitted or `true`. \*\* The `required` field is only available for User Selects in modals. It is ignored in messages. \*\*\* Using `disabled` in a modal will result in an error. Modals can not currently have disabled components in them. ###### Select Default Value Structure | Field | Type | Description | | ----- | --------- | ----------------------------------------------------------------------------- | | id | snowflake | ID of a user, role, or channel | | type | string | Type of value that `id` represents. Either `"user"`, `"role"`, or `"channel"` | ###### User Select Interaction Response Structure | Field | Type | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | type\* | integer | `5` for a User Select | | component\_type\* | integer | `5` for a User Select | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | resolved | [resolved data](/developers/interactions/receiving-and-responding#interaction-object-resolved-data-structure) | Resolved entities from selected options | | values | array of snowflakes | IDs of the selected users | \* In message interaction responses `component_type` will be returned and in modal interaction responses `type` will be returned. ###### Examples Example of a User Select with two people and an app in a server ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 1, // ComponentType.ACTION_ROW "components": [ { "type": 5, // ComponentType.USER_SELECT "custom_id": "user_select", "placeholder": "Select a user" } ] } ] } ``` When a user interacts with a User Select in a message, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. `members` and `users` may both be present in the `resolved` object when a user is selected. ```jsonc theme={"system"} { "type": 3, // InteractionType.MESSAGE_COMPONENT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "component_type": 5, // ComponentType.USER_SELECT "id": 2, "custom_id": "user_select", "values": [ "1111111111111111111", ], "resolved": { "members": { "1111111111111111111": { "avatar": null, "banner": null, "collectibles": null, "communication_disabled_until": null, "flags": 0, "joined_at": "2025-05-16T22:51:16.692000+00:00", "nick": null, "pending": false, "permissions": "2248473465835073", "premium_since": null, "roles": [ "2222222222222222222" ], "unusual_dm_activity_until": null } }, "users": { "1111111111111111111": { "avatar": "d54e87d20539fe9aad2f2cebe56809a2", "avatar_decoration_data": null, "bot": true, "clan": null, "collectibles": null, "discriminator": "9062", "display_name_styles": null, "global_name": null, "id": "1111111111111111111", "primary_guild": null, "public_flags": 524289, "username": "ExampleBot" } } } }, } ``` Example of a modal with a User Select ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "user_modal", "title": "User Chooser", "components": [ { "type": 18, // ComponentType.LABEL "label": "Choose your users", "component": { "type": 5, // ComponentType.USER_SELECT "custom_id": "user_selected", "max_values": 5, "required": true } } ] } } ``` When a user submits a modal that contains a User Select, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "user_modal", "components": [ { "component": { "custom_id": "user_selected", "id": 2, "type": 5, "values": [ "11111111111111111" ] }, "id": 1, "type": 18 } ], "resolved": { "members": { "11111111111111111": { "avatar": null, "banner": null, "collectibles": null, "communication_disabled_until": null, "flags": 0, "joined_at": "2025-04-02T23:07:21.476000+00:00", "nick": "Ant", "pending": false, "permissions": "4503599627370495", "premium_since": null, "roles": [ "1357409927680889032" ], "unusual_dm_activity_until": null } }, "users": { "11111111111111111": { "avatar": "a_b15bd8ee42e3c3d9a7de129fee60bc84", "avatar_decoration_data": null, "clan": null, "collectibles": { "nameplate": { "asset": "nameplates/spell/white_mana/", "expires_at": null, "label": "COLLECTIBLES_SPELL_WHITE_MANA_NP_A11Y", "palette": "bubble_gum", "sku_id": "1379220459203072050" } }, "discriminator": "0", "display_name_styles": { "colors": [ 16777215 ], "effect_id": 4, "font_id": 3 }, "global_name": "Anthony", "id": "11111111111111111", "primary_guild": null, "public_flags": 65, "username": "actuallyanthony" } } } } } ``` *** ## Role Select A Role Select is an interactive component that allows users to select one or more roles in a message or modal. Options are automatically populated based on the server's available roles. Role Selects can be configured for both single-select and multi-select behavior. When a user finishes making their choice(s) your app receives an [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure). Role Selects are available in messages and modals. They must be placed inside an [Action Row](/developers/components/reference#action-row) in messages and a [Label](/developers/components/reference#label) in modals. ###### Role Select Structure | Field | Type | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | integer | `6` for role select | | id? | integer | Optional identifier for component | | custom\_id | string | ID for the select menu; 1-100 characters | | placeholder? | string | Placeholder text if nothing is selected; max 150 characters | | default\_values? | array of [default value objects](/developers/components/reference#user-select-select-default-value-structure) | List of default values for auto-populated select menu components; number of default values must be in the range defined by `min_values` and `max_values` | | min\_values?\* | integer | Minimum number of items that must be chosen (defaults to 1); min 0 (see note), max 25 | | max\_values? | integer | Maximum number of items that can be chosen (defaults to 1); max 25 | | required?\*\* | boolean | Whether the role select is required to answer in a modal (defaults to `true`) | | disabled?\*\*\* | boolean | Whether select menu is disabled in a message (defaults to `false`) | \* `min_values` must be either omitted or at least `1` if `required` is omitted or `true`. \*\* The `required` field is only available for Role Selects in modals. It is ignored in messages. \*\*\* Using `disabled` in a modal will result in an error. Modals can not currently have disabled components in them. ###### Role Select Interaction Response Structure | Field | Type | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | type\* | integer | `6` for a Role Select | | component\_type\* | integer | `6` for a Role Select | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | resolved | [resolved data](/developers/interactions/receiving-and-responding#interaction-object-resolved-data-structure) | Resolved entities from selected options | | values | array of snowflakes | IDs of the selected roles | \* In message interaction responses `component_type` will be returned and in modal interaction responses `type` will be returned. ###### Examples Example of a Role Select allowing up to 3 choices ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 1, // ComponentType.ACTION_ROW "components": [ { "type": 6, // ComponentType.ROLE_SELECT "custom_id": "role_ids", "placeholder": "Which roles?", "min_values": 1, "max_values": 3 } ] } ] } ``` When a user interacts with a Role Select in a message, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 3, // InteractionType.MESSAGE_COMPONENT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "component_type": 6, // ComponentType.ROLE_SELECT "id": 2, "custom_id": "role_ids", "values": [ "222222222222222222", ], "resolved": { "roles": { "222222222222222222": { "color": 12745742, "colors": { "primary_color": 12745742, "secondary_color": null, "tertiary_color": null }, "description": null, "flags": 0, "hoist": false, "icon": null, "id": "222222222222222222", "managed": false, "mentionable": true, "name": "Developer", "permissions": "0", "position": 2, "unicode_emoji": "🔧" } } } }, } ``` Example of a modal with a Role Select ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "role_modal", "title": "Role Select", "components": [ { "type": 18, "label": "Select which roles to assign", "component": { "type": 6, "custom_id": "roles_selected", "max_values": 10, "required": true } } ] } } ``` When a user submits a modal that contains a Role Select, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "role_modal", "components": [ { "component": { "custom_id": "roles_selected", "id": 2, "type": 6, "values": [ "1362213912946147499", "1357409927680889032" ] }, "id": 1, "type": 18 } ], "resolved": { "roles": { "1357409927680889032": { "color": 7419530, "colors": { "primary_color": 7419530, "secondary_color": null, "tertiary_color": null }, "description": null, "flags": 0, "hoist": true, "icon": null, "id": "1357409927680889032", "managed": false, "mentionable": true, "name": "Player", "permissions": "2249596494938111", "position": 3, "unicode_emoji": "🎮" }, "1362213912946147499": { "color": 11342935, "colors": { "primary_color": 11342935, "secondary_color": null, "tertiary_color": null }, "description": null, "flags": 0, "hoist": false, "icon": null, "id": "1362213912946147499", "managed": false, "mentionable": false, "name": "Mod", "permissions": "0", "position": 1, "unicode_emoji": "🔨" } } } } } ``` *** ## Mentionable Select A Mentionable Select is an interactive component that allows users to select one or more mentionables in a message or modal. Options are automatically populated based on available mentionables in the server. Mentionable Selects can be configured for both single-select and multi-select behavior. When a user finishes making their choice(s), your app receives an [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure). Mentionable Selects are available in messages and modals. They must be placed inside an [Action Row](/developers/components/reference#action-row) in messages and a [Label](/developers/components/reference#label) in modals. ###### Mentionable Select Structure | Field | Type | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | integer | `7` for mentionable select | | id? | integer | Optional identifier for component | | custom\_id | string | ID for the select menu; 1-100 characters | | placeholder? | string | Placeholder text if nothing is selected; max 150 characters | | default\_values? | array of [default value objects](/developers/components/reference#user-select-select-default-value-structure) | List of default values for auto-populated select menu components; number of default values must be in the range defined by `min_values` and `max_values` | | min\_values?\* | integer | Minimum number of items that must be chosen (defaults to 1); min 0 (see note), max 25 | | max\_values? | integer | Maximum number of items that can be chosen (defaults to 1); max 25 | | required?\*\* | boolean | Whether the mentionable select is required to answer in a modal (defaults to `true`) | | disabled?\*\*\* | boolean | Whether select menu is disabled in a message (defaults to `false`) | \* `min_values` must be either omitted or at least `1` if `required` is omitted or `true`. \*\* The `required` field is only available for Mentionable Selects in modals. It is ignored in messages. \*\*\* Using `disabled` in a modal will result in an error. Modals can not currently have disabled components in them. ###### Mentionable Select Interaction Response Structure | Field | Type | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | type\* | integer | `7` for a Mentionable Select | | component\_type\* | integer | `7` for a Mentionable Select | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | resolved | [resolved data](/developers/interactions/receiving-and-responding#interaction-object-resolved-data-structure) | Resolved entities from selected options | | values | array of snowflakes | IDs of the selected mentionables | \* In message interaction responses `component_type` will be returned and in modal interaction responses `type` will be returned. ###### Examples Example of a Mentionable Select from the code below ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 1, // ComponentType.ACTION_ROW "components": [ { "type": 7, // ComponentType.MENTIONABLE_SELECT "custom_id": "who_to_ping", "placeholder": "Who?", } ] } ] } ``` When a user interacts with a Mentionable Select in a message, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. `members` and `users` may both be present in the `resolved` object when a user is selected. ```jsonc theme={"system"} { "type": 3, // InteractionType.MESSAGE_COMPONENT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "component_type": 7, // ComponentType.MENTIONABLE_SELECT "id": 2, "custom_id": "who_to_ping", "values": [ "111111111111111111", "222222222222222222", ], "resolved": { "members": { "1111111111111111111": { "avatar": null, "banner": null, "collectibles": null, "communication_disabled_until": null, "flags": 0, "joined_at": "2025-05-16T22:51:16.692000+00:00", "nick": null, "pending": false, "permissions": "2248473465835073", "premium_since": null, "roles": [ "2222222222222222222" ], "unusual_dm_activity_until": null } }, "users": { "1111111111111111111": { "avatar": "d54e87d20539fe9aad2f2cebe56809a2", "avatar_decoration_data": null, "bot": true, "clan": null, "collectibles": null, "discriminator": "9062", "display_name_styles": null, "global_name": null, "id": "1111111111111111111", "primary_guild": null, "public_flags": 524289, "username": "ExampleBot" } }, "roles": { "222222222222222222": { "color": 12745742, "colors": { "primary_color": 12745742, "secondary_color": null, "tertiary_color": null }, "description": null, "flags": 0, "hoist": false, "icon": null, "id": "222222222222222222", "managed": false, "mentionable": true, "name": "Developer", "permissions": "0", "position": 2, "unicode_emoji": "🔧" } } } }, } ``` Example of a Mentionable Select from the code below ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "mentionable_modal", "title": "Unmentionables", "components": [ { "type": 18, "label": "Who gets mentioned?", "component": { "type": 7, "custom_id": "mentionables_selected", "required": true } } ] } } ``` When a user submits a modal that contains a Mentionable Select, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "mentionable_modal", "components": [ { "component": { "custom_id": "mentionables_selected", "id": 2, "type": 7, "values": [ "1361539726405926952" ] }, "id": 1, "type": 18 } ], "resolved": { "roles": { "1361539726405926952": { "color": 12745742, "colors": { "primary_color": 12745742, "secondary_color": null, "tertiary_color": null }, "description": null, "flags": 0, "hoist": false, "icon": null, "id": "1361539726405926952", "managed": false, "mentionable": true, "name": "Developer", "permissions": "0", "position": 2, "unicode_emoji": "🔧" } } } } } ``` *** ## Channel Select A Channel Select is an interactive component that allows users to select one or more channels in a message or modal. Options are automatically populated based on available channels in the server and can be filtered by channel types. Channel Selects can be configured for both single-select and multi-select behavior. When a user finishes making their choice(s) your app receives an [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure). Channel Selects are available in messages and modals. They must be placed inside an [Action Row](/developers/components/reference#action-row) in messages and a [Label](/developers/components/reference#label) in modals. ###### Channel Select Structure | Field | Type | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | type | integer | `8` for channel select | | id? | integer | Optional identifier for component | | custom\_id | string | ID for the select menu; 1-100 characters | | channel\_types? | array of [channel types](/developers/resources/channel#channel-object-channel-types) | List of channel types to include in the channel select component | | placeholder? | string | Placeholder text if nothing is selected; max 150 characters | | default\_values? | array of [default value objects](/developers/components/reference#user-select-select-default-value-structure) | List of default values for auto-populated select menu components; number of default values must be in the range defined by `min_values` and `max_values` | | min\_values?\* | integer | Minimum number of items that must be chosen (defaults to 1); min 0 (see note), max 25 | | max\_values? | integer | Maximum number of items that can be chosen (defaults to 1); max 25 | | required?\*\* | boolean | Whether the channel select is required to answer in a modal (defaults to `true`) | | disabled?\*\*\* | boolean | Whether select menu is disabled in a message (defaults to `false`) | \* `min_values` must be either omitted or at least `1` if `required` is omitted or `true`. \*\* The `required` field is only available for Channel Selects in modals. It is ignored in messages. \*\*\* Using `disabled` in a modal will result in an error. Modals can not currently have disabled components in them. ###### Channel Select Interaction Response Structure | Field | Type | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | type\* | integer | `8` for a Channel Select | | component\_type\* | integer | `8` for a Channel Select | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | resolved | [resolved data](/developers/interactions/receiving-and-responding#interaction-object-resolved-data-structure) | Resolved entities from selected options | | values | array of snowflakes | IDs of the selected channels | \* In message interaction responses `component_type` will be returned and in modal interaction responses `type` will be returned. ###### Examples Example of a Channel Select for text channels ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 1, // ComponentType.ACTION_ROW "components": [ { "type": 8, // ComponentType.CHANNEL_SELECT "custom_id": "notification_channel", "channel_types": [0], // ChannelType.TEXT "placeholder": "Which text channel?" } ] } ] } ``` When a user interacts with a Channel Select in a message, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 3, // InteractionType.MESSAGE_COMPONENT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "component_type": 8, // ComponentType.CHANNEL_SELECT "id": 2, "custom_id": "notification_channel", "values": [ "333333333333333333", ], "resolved": { "channels": { "333333333333333333": { "flags": 0, "guild_id": "44444444444444444", "id": "333333333333333333", "last_message_id": null, "name": "playtesting", "nsfw": false, "parent_id": "5555555555555555", "permissions": "4503599627370495", "position": 1, "rate_limit_per_user": 0, "topic": null, "type": 0 // ChannelType.TEXT } } } }, } ``` Example of a modal with a Channel Select ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "channel_modal", "title": "Lockdown", "components": [ { "type": 18, "label": "Which channel should be locked?", "component": { "type": 8, "custom_id": "channel_selected", "required": true } } ] } } ``` When a user submits a modal that contains a Channel Select, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "channel_modal", "components": [ { "component": { "custom_id": "channel_selected", "id": 2, "type": 8, "values": [ "1357483683627663450" ] }, "id": 1, "type": 18 } ], "resolved": { "channels": { "1357483683627663450": { "flags": 0, "guild_id": "1111111111111111", "id": "1357483683627663450", "last_message_id": null, "name": "playtesting", "nsfw": false, "parent_id": "1357129309164404938", "permissions": "4503599627370495", "position": 1, "rate_limit_per_user": 0, "topic": null, "type": 0 } } } } } ``` *** ## Section A Section is a top-level layout component that allows you to contextually associate content with an accessory component. The typical use-case is to contextually associate [text content](/developers/components/reference#text-display) with an [accessory](/developers/components/reference#section-section-accessory-components). Sections are currently only available in messages. To use this component in messages you must send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2) which can be activated on a per-message basis. ###### Section Structure | Field | Type | Description | | ---------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | | type | integer | `9` for section component | | id? | integer | Optional identifier for component | | components | array of [section child components](/developers/components/reference#section-section-child-components) | One to three child components representing the content of the section that is contextually associated to the accessory | | accessory | [section accessory component](/developers/components/reference#section-section-accessory-components) | A component that is contextually associated to the content of the section | Don't hardcode `components` to contain only text components. We may add other components in the future. Similarly, `accessory` may be expanded to include other components in the future. ###### Section Child Components | Available Components | | ------------------------------------------------------------- | | [Text Display](/developers/components/reference#text-display) | ###### Section Accessory Components | Available Components | | ------------------------------------------------------- | | [Button](/developers/components/reference#button) | | [Thumbnail](/developers/components/reference#thumbnail) | ###### Examples Example of a Section showing a fake game changelog and a thumbnail ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 9, // ComponentType.SECTION "components": [ { "type": 10, // ComponentType.TEXT_DISPLAY "content": "# Real Game v7.3" }, { "type": 10, // ComponentType.TEXT_DISPLAY "content": "Hope you're excited, the update is finally here! Here are some of the changes:\n- Fixed a bug where certain treasure chests wouldn't open properly\n- Improved server stability during peak hours\n- Added a new type of gravity that will randomly apply when the moon is visible in-game\n- Every third thursday the furniture will scream your darkest secrets to nearby npcs" }, { "type": 10, // ComponentType.TEXT_DISPLAY "content": "-# That last one wasn't real, but don't use voice chat near furniture just in case..." } ], "accessory": { "type": 11, // ComponentType.THUMBNAIL "media": { "url": "https://websitewithopensourceimages/gamepreview.webp" } } } ] } ``` *** ## Text Display A Text Display is a content component that allows you to add markdown formatted text, including mentions (users, roles, etc) and emojis. The behavior of this component is extremely similar to the [`content` field of a message](/developers/resources/message#message-object), but allows you to add multiple text components, controlling the layout of your message. When sent in a message, pingable mentions (@user, @role, etc) present in this component will ping and send notifications based on the value of the [allowed mention object](/developers/resources/message#allowed-mentions-object) set in [`message.allowed_mentions`](/developers/resources/message#message-object). To use this component in messages you must send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2) which can be activated on a per-message basis. ###### Text Display Structure | Field | Type | Description | | ------- | ------- | ------------------------------------------------ | | type | integer | `10` for text display | | id? | integer | Optional identifier for component | | content | string | Text that will be displayed similar to a message | ###### Text Display Interaction Response Structure | Field | Type | Description | | ----- | ------- | ----------------------------------- | | type | integer | `10` for a Text Display | | id | integer | Unique identifier for the component | ###### Examples Example of a Text Display with markdown ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 10, // ComponentType.TEXT_DISPLAY "content": "# This is a Text Display\nAll the regular markdown rules apply\n- You can make lists\n- You can use `code blocks`\n- You can use [links](http://watchanimeattheoffice.com/)\n- Even :blush: :star_struck: :exploding_head:\n- Spoiler alert: ||these too!||" } ] } ``` Example of a Text Display from the code below ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "jail_modal", "title": "Jail", "components": [ { "type": 10, "content": "This action will move the selected user to the selected voice channel and take away all their permissions **for 1 hour**." }, { "type": 18, "label": "Choose a user", "component": { "type": 5, "custom_id": "user_selected", "required": true } }, { "type": 18, "label": "Where should they be sent?", "component": { "type": 8, "custom_id": "channel_selected", "channel_types": [ 2 ], "required": true } } ] } } ``` *** ## Thumbnail A Thumbnail is a content component that displays visual media in a small form-factor. It is intended as an accessory for to other content, and is primarily usable with [sections](/developers/components/reference#section). The media displayed is defined by the [unfurled media item](/developers/components/reference#unfurled-media-item) structure, which supports both uploaded media and externally hosted media. Thumbnails are currently only available in messages as an accessory in a [section](/developers/components/reference#section). Thumbnails currently only support images, including animated formats like GIF and WEBP. Videos are not supported at this time. To use this component, you need to send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2), which can be activated on a per-message basis. ###### Thumbnail Structure | Field | Type | Description | | ------------ | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | type | integer | `11` for thumbnail component | | id? | integer | Optional identifier for component | | media | [unfurled media item](/developers/components/reference#unfurled-media-item) | A url or attachment provided as an [unfurled media item](/developers/components/reference#unfurled-media-item) | | description? | ?string | Alt text for the media, max 1024 characters | | spoiler? | boolean | Whether the thumbnail should be a spoiler (or blurred out). Defaults to `false` | ###### Examples Example of a Thumbnail in a Section from the code below ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 9, // ComponentType.SECTION "components": [ { "type": 10, // ComponentType.TEXT_DISPLAY "content": "# Real Game v7.3" }, { "type": 10, // ComponentType.TEXT_DISPLAY "content": "Hope you're excited, the update is finally here! Here are some of the changes:\n- Fixed a bug where certain treasure chests wouldn't open properly\n- Improved server stability during peak hours\n- Added a new type of gravity that will randomly apply when the moon is visible in-game\n- Every third thursday the furniture will scream your darkest secrets to nearby npcs" }, { "type": 10, // ComponentType.TEXT_DISPLAY "content": "-# That last one wasn't real, but don't use voice chat near furniture just in case..." } ], "accessory": { "type": 11, // ComponentType.THUMBNAIL "media": { "url": "https://websitewithopensourceimages/gamepreview.webp" } } } ] } ``` *** ## Media Gallery A Media Gallery is a top-level content component that allows you to display 1-10 media attachments in an organized gallery format. Each item can have optional descriptions and can be marked as spoilers. Media Galleries are currently only available in messages. To use this component in messages you must send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2) which can be activated on a per-message basis. ###### Media Gallery Structure | Field | Type | Description | | ----- | ----------------------------------------------------------------------------------------------------------- | --------------------------------- | | type | integer | `12` for media gallery component | | id? | integer | Optional identifier for component | | items | array of [media gallery items](/developers/components/reference#media-gallery-media-gallery-item-structure) | 1 to 10 media gallery items | ###### Media Gallery Item Structure | Field | Type | Description | | ------------ | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | media | [unfurled media item](/developers/components/reference#unfurled-media-item) | A url or attachment provided as an [unfurled media item](/developers/components/reference#unfurled-media-item) | | description? | ?string | Alt text for the media, max 1024 characters | | spoiler? | boolean | Whether the media should be a spoiler (or blurred out). Defaults to `false` | ###### Examples Example of a Media Gallery showing screenshots from live webcam feeds ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 10, // ComponentType.TEXT_DISPLAY "content": "Live webcam shots as of 18-04-2025 at 12:00 UTC" }, { "type": 12, // ComponentType.MEDIA_GALLERY "items": [ { "media": {"url": "https://livevideofeedconvertedtoimage/webcam1.webp"}, "description": "An aerial view looking down on older industrial complex buildings. The main building is white with many windows and pipes running up the walls." }, { "media": {"url": "https://livevideofeedconvertedtoimage/webcam2.webp"}, "description": "An aerial view of old broken buildings. Nature has begun to take root in the rooftops. A portion of the middle building's roof has collapsed inward. In the distant haze you can make out a far away city." }, { "media": {"url": "https://livevideofeedconvertedtoimage/webcam3.webp"}, "description": "A street view of a downtown city. Prominently in photo are skyscrapers and a domed building" } ] } ] } ``` *** ## File A File is a top-level content component that allows you to display an [uploaded file](/developers/components/reference#uploading-a-file) as an attachment to the message and reference it in the component. Each file component can only display 1 attached file, but you can upload multiple files and add them to different file components within your payload. Files are currently only available in messages. The File component only supports using the `attachment://` protocol in [unfurled media item](/developers/components/reference#unfurled-media-item) To use this component in messages you must send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2) which can be activated on a per-message basis. ###### File Structure | Field | Type | Description | | -------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | | type | integer | `13` for a file component | | id? | integer | Optional identifier for component | | file | [unfurled media item](/developers/components/reference#unfurled-media-item) | This unfurled media item is unique in that it **only** supports attachment references using the `attachment://` syntax | | spoiler? | boolean | Whether the media should be a spoiler (or blurred out). Defaults to `false` | | name? | string | The name of the file. This field is ignored and provided by the API as part of the response | | size? | integer | The size of the file in bytes. This field is ignored and provided by the API as part of the response | ###### Examples Example of a File showing a download for a game and manual This example makes use of the `attachment://` protocol functionality in [unfurled media item](/developers/components/reference#unfurled-media-item). ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 10, // ComponentType.TEXT_DISPLAY "content": "# New game version released for testing!\nGrab the game here:" }, { "type": 13, // ComponentType.FILE "file": { "url": "attachment://game.zip" } }, { "type": 10, // ComponentType.TEXT_DISPLAY "content": "Latest manual artwork here:" }, { "type": 13, // ComponentType.FILE "file": { "url": "attachment://manual.pdf" } } ] } ``` *** ## Separator A Separator is a top-level layout component that adds vertical padding and visual division between other components. Separators are currently only available in messages. To use this component in messages you must send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2) which can be activated on a per-message basis. ###### Separator Structure | Field | Type | Description | | -------- | ------- | --------------------------------------------------------------------------------------- | | type | integer | `14` for separator component | | id? | integer | Optional identifier for component | | divider? | boolean | Whether a visual divider should be displayed in the component. Defaults to `true` | | spacing? | integer | Size of separator padding—`1` for small padding, `2` for large padding. Defaults to `1` | ###### Examples Example of a separator with large spacing dividing content ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 10, // ComponentType.TEXT_DISPLAY "content": "It's dangerous to go alone!" }, { "type": 14, // ComponentType.SEPARATOR "divider": true, "spacing": 1 }, { "type": 10, // ComponentType.TEXT_DISPLAY "content": "Take this." } ] } ``` *** ## Container A Container is a top-level layout component. Containers offer the ability to visually encapsulate a collection of components and have an optional customizable accent color bar. Containers are currently only available in messages. To use this component in messages you must send the [message flag](/developers/resources/message#message-object-message-flags) `1 << 15` (IS\_COMPONENTS\_V2) which can be activated on a per-message basis. ###### Container Structure | Field | Type | Description | | -------------- | ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | | type | integer | `17` for container component | | id? | integer | Optional identifier for component | | components | array of [container child components](/developers/components/reference#container-container-child-components) | Child components that are encapsulated within the Container | | accent\_color? | ?integer | Color for the accent on the container as RGB from `0x000000` to `0xFFFFFF` | | spoiler? | boolean | Whether the container should be a spoiler (or blurred out). Defaults to `false`. | ###### Container Child Components | Available Components | | --------------------------------------------------------------- | | [Action Row](/developers/components/reference#action-row) | | [Text Display](/developers/components/reference#text-display) | | [Section](/developers/components/reference#section) | | [Media Gallery](/developers/components/reference#media-gallery) | | [Separator](/developers/components/reference#separator) | | [File](/developers/components/reference#file) | ###### Examples Example of a container showing text, image, and buttons for a wild enemy encounter ```jsonc theme={"system"} { "flags": 32768, "components": [ { "type": 17, // ComponentType.CONTAINER "accent_color": 703487, "components": [ { "type": 10, // ComponentType.TEXT_DISPLAY "content": "# You have encountered a wild coyote!" }, { "type": 12, // ComponentType.MEDIA_GALLERY "items": [ { "media": {"url": "https://websitewithopensourceimages/coyote.webp"}, } ] }, { "type": 10, // ComponentType.TEXT_DISPLAY "content": "What would you like to do?" }, { "type": 1, // ComponentType.ACTION_ROW "components": [ { "type": 2, // ComponentType.BUTTON "custom_id": "pet_coyote", "label": "Pet it!", "style": 1 }, { "type": 2, // ComponentType.BUTTON "custom_id": "feed_coyote", "label": "Attempt to feed it", "style": 2 }, { "type": 2, // ComponentType.BUTTON "custom_id": "run_away", "label": "Run away!", "style": 4 } ] } ] } ] } ``` *** ## Label A Label is a top-level layout component. Labels wrap modal components with text as a label and optional description. The `description` may display above or below the `component` depending on the platform. ###### Label Structure | Field | Type | Description | | ------------ | -------------------------------------------------------------------------------------- | -------------------------------------------------------------- | | type | integer | `18` for a label | | id? | integer | Optional identifier for component | | label | string | The label text; max 45 characters | | description? | string | An optional description text for the label; max 100 characters | | component | [label child component](/developers/components/reference#label-label-child-components) | The component within the label | ###### Label Child Components | Available Components | | ------------------------------------------------------------------------- | | [Text Input](/developers/components/reference#text-input) | | [String Select](/developers/components/reference#string-select) | | [User Select](/developers/components/reference#user-select) | | [Role Select](/developers/components/reference#role-select) | | [Mentionable Select](/developers/components/reference#mentionable-select) | | [Channel Select](/developers/components/reference#channel-select) | | [File Upload](/developers/components/reference#file-upload) | | [Radio Group](/developers/components/reference#radio-group) | | [Checkbox Group](/developers/components/reference#checkbox-group) | | [Checkbox](/developers/components/reference#checkbox) | ###### Label Interaction Response Structure | Field | Type | Description | | --------- | -------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | | type | integer | `18` for a Label | | id | integer | Unique identifier for the component | | component | [label interaction response child component](/developers/components/reference#label-label-interaction-response-child-components) | The component within the label | ###### Label Interaction Response Child Components | Available Components | | --------------------------------------------------------------------------------------------------------------------------- | | [Text Input](/developers/components/reference#text-input-text-input-interaction-response-structure) | | [String Select](/developers/components/reference#string-select-string-select-interaction-response-structure) | | [User Select](/developers/components/reference#user-select-user-select-interaction-response-structure) | | [Role Select](/developers/components/reference#role-select-role-select-interaction-response-structure) | | [Mentionable Select](/developers/components/reference#mentionable-select-mentionable-select-interaction-response-structure) | | [Channel Select](/developers/components/reference#channel-select-channel-select-interaction-response-structure) | | [File Upload](/developers/components/reference#file-upload-file-upload-interaction-response-structure) | | [Radio Group](/developers/components/reference#radio-group-interaction-response-structure) | | [Checkbox Group](/developers/components/reference#checkbox-group-interaction-response-structure) | | [Checkbox](/developers/components/reference#checkbox-interaction-response-structure) | ###### Examples A modal with Text Input in a Label ```jsonc theme={"system"} { "type": 9, // InteractionCallbackType.MODAL "data": { "custom_id": "game_feedback_modal", "title": "Game Feedback", "components": [ { "type": 18, // ComponentType.LABEL "label": "What did you find interesting about the game?", "description": "Please give us as much detail as possible so we can improve the game!", "component": { "type": 4, // ComponentType.TEXT_INPUT "custom_id": "game_feedback", "style": 2, "min_length": 100, "max_length": 4000, "placeholder": "Write your feedback here...", "required": true } } ] } } ``` *** ## File Upload File Upload is an interactive component that allows users to upload files in modals. File Uploads can be configured to have a minimum and maximum number of files between 0 and 10, along with `required` for if the upload is required to submit the modal. The max file size a user can upload is based on the user's upload limit in that channel. File Uploads are available on modals. They must be placed inside a [Label](/developers/components/reference#label). ###### File Upload Structure | Field | Type | Description | | -------------- | ------- | ------------------------------------------------------------------------------------------------------ | | type | integer | `19` for file upload | | id? | integer | Optional identifier for component | | custom\_id | string | ID for the file upload; 1-100 characters | | min\_values?\* | integer | Minimum number of items that must be uploaded (defaults to 1); min 0 (see note), max 10 | | max\_values? | integer | Maximum number of items that can be uploaded (defaults to 1); max 10 | | required? | boolean | Whether the file upload requires files to be uploaded before submitting the modal (defaults to `true`) | \* `min_values` must be either omitted or at least `1` if `required` is omitted or `true`. ###### File Upload Interaction Response Structure | Field | Type | Description | | ---------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | type | integer | `19` for a File Upload | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | values | array of snowflakes | IDs of the uploaded files found in the [resolved data](/developers/interactions/receiving-and-responding#interaction-object-resolved-data-structure) | ###### Examples Example of a modal with a File Upload ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "bug_submit_modal", "title": "Bug Submission", "components": [ { "type": 18, // ComponentType.LABEL "label": "File Upload", "description": "Please upload a screenshot or other image that shows the bug you encountered.", "component": { "type": 19, // ComponentType.FILE_UPLOAD "custom_id": "file_upload", "min_values": 1, "max_values": 10, "required": true } } ] } } ``` When a user submits a modal that contains a File Upload, this is the basic form of the interaction data payload you will receive. The full payload is available in the [interaction](/developers/interactions/receiving-and-responding#interaction-object-interaction-structure) reference. ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "components": [ { "component": { "custom_id": "file_upload", "id": 2, "type": 19, "values": [ "111111111111111111111" ] }, "id": 1, "type": 18 } ], "custom_id": "bug_submit_modal", "resolved": { "attachments": { "111111111111111111111": { "content_type": "image/png", "ephemeral": true, "filename": "bug.png", "height": 604, "id": "111111111111111111111", "placeholder": "/PcBAoBQydvKesabEIoMsdg=", "placeholder_version": 1, "proxy_url": "https://media.discordapp.net/ephemeral-attachments/2222222222222222222/111111111111111111111/bug.png?ex=68dc7ce1&is=68db2b61&hm=5954f90117ccf8716ffa6c7f97a778a0d039810c9584045f400d8a9fff590768&", "size": 241394, "url": "https://cdn.discordapp.com/ephemeral-attachments/2222222222222222222/111111111111111111111/bug.png?ex=68dc7ce1&is=68db2b61&hm=5954f90117ccf8716ffa6c7f97a778a0d039810c9584045f400d8a9fff590768&", "width": 2482 } } } } } ``` *** ## Radio Group A Radio Group is an interactive component for selecting exactly one option from a defined list. Radio Groups are available in modals and must be placed inside a [Label](/developers/components/reference#label). ### Radio Group Structure | Field | Type | Description | | ---------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | | type | integer | `21` for radio group | | id? | integer | Optional identifier for component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | options | array of [radio group options](/developers/components/reference#radio-group-option-structure) | List of options to show; min 2, max 10 | | required? | boolean | Whether a selection is required to submit the modal (defaults to `true`) | ### Radio Group Option Structure | Field | Type | Description | | ------------ | ------- | ------------------------------------------------------- | | value | string | Dev-defined value of the option; max 100 characters | | label | string | User-facing label of the option; max 100 characters | | description? | string | Optional description for the option; max 100 characters | | default? | boolean | Shows the option as selected by default | ### Radio Group Interaction Response Structure | Field | Type | Description | | ---------- | ------- | -------------------------------------------------------------------- | | type | integer | `21` for a Radio Group | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | value | ?string | The value of the selected option, or `null` if no option is selected | ### Examples Example of a modal with a Radio Group ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "class_selection_modal", "title": "Class Selection", "components": [ { "type": 18, // ComponentType.LABEL "label": "Choose your class", "description": "Your class detertmines the style of play for your character.", "component": { "type": 21, // ComponentType.RADIO_GROUP "custom_id": "class_radio", "options": [ {"value": "warrior", "label": "Warrior", "description": "Strong and brave"}, {"value": "rogue", "label": "Rogue", "description": "Weak and squishy"}, {"value": "wizard", "label": "Wizard", "description": "Nerd"}, {"value": "bard", "label": "Bard", "description": "Annoys everyone"}, {"value": "witch_doctor", "label": "Witch Doctor", "description": "Actually a pretty cool option"} ] } } ] } } ``` ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "class_selection_modal", "components": [ { "id": 1, "type": 18, // ComponentType.LABEL "component": { "custom_id": "class_radio", "id": 2, "type": 21, // ComponentType.RADIO_GROUP "value": "warrior" } } ] } } ``` *** ## Checkbox Group A Checkbox Group is an interactive component for selecting one or many options via checkboxes. Checkbox Groups are available in modals and must be placed inside a [Label](/developers/components/reference#label). ### Checkbox Group Structure | Field | Type | Description | | -------------- | --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | type | integer | `22` for checkbox group | | id? | integer | Optional identifier for component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | options | array of [checkbox group options](/developers/components/reference#checkbox-group-option-structure) | List of options to show; min 1, max 10 | | min\_values?\* | integer | Minimum number of items that must be chosen; min 0, max 10 (defaults to 1); | | max\_values? | integer | Maximum number of items that can be chosen; min 1, max 10 (defaults to the number of options) | | required? | boolean | Whether selecting within the group is required (defaults to `true`) | \* `min_values` must be either omitted or at least `1` if `required` is omitted or `true`. ### Checkbox Group Option Structure | Field | Type | Description | | ------------ | ------- | ------------------------------------------------------- | | value | string | Dev-defined value of the option; max 100 characters | | label | string | User-facing label of the option; max 100 characters | | description? | string | Optional description for the option; max 100 characters | | default? | boolean | Shows the option as selected by default | ### Checkbox Group Interaction Response Structure | Field | Type | Description | | ---------- | ---------------- | ------------------------------------------------------------------------------------- | | type | integer | `22` for a Checkbox Group | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | values | array of strings | The values of the selected options, or an empty array `[]` if no options are selected | ### Examples Example of a modal with a Checkbox Group ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "day_selection_modal", "title": "Study Days", "components": [ { "type": 18, // ComponentType.LABEL "label": "Which days are you free?", "description": "Choose all of the days you're able to meet up.", "component": { "type": 22, // ComponentType.CHECKBOX_GROUP "custom_id": "event_checkbox", "options": [ {"value": "march-4", "label": "March 4th"}, {"value": "march-5", "label": "March 5th"}, {"value": "march-7", "label": "March 7th", "description": "I know this is a Saturday and is tough"}, {"value": "march-9", "label": "March 9th"}, {"value": "march-10", "label": "March 10th"} ] } } ] } } ``` ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "day_selection_modal", "components": [ { "id": 1, "type": 18, // ComponentType.LABEL "component": { "custom_id": "event_checkbox", "id": 2, "type": 22, // ComponentType.CHECKBOX_GROUP "values": [ "march-5", "march-10", "march-4" ] } } ] } } ``` *** ## Checkbox A Checkbox is a single interactive component for simple yes/no style questions. Checkboxes are available in modals and must be placed inside a [Label](/developers/components/reference#label). ### Checkbox Structure | Field | Type | Description | | ---------- | ------- | ------------------------------------------------------------ | | type | integer | `23` for checkbox | | id? | integer | Optional identifier for component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | default? | boolean | Whether the checkbox is selected by default | While you can't set a checkbox as required, you can use a [Checkbox Group](/developers/components/reference#checkbox-group) with a single option and `required` to achieve similar functionality. ### Checkbox Interaction Response Structure | Field | Type | Description | | ---------- | ------- | ------------------------------------------------------------------- | | type | integer | `23` for a Checkbox | | id | integer | Unique identifier for the component | | custom\_id | string | Developer-defined identifier for the input; 1-100 characters | | value | boolean | The state of the checkbox (`true` if checked, `false` if unchecked) | ### Examples Example of a modal with a Checkbox ```jsonc theme={"system"} { "type": 9, "data": { "custom_id": "secret_note_modal", "title": "Secret Note", "components": [ { "type": 18, // ComponentType.LABEL "label": "Do you like me?", "description": "😳😳😳", "component": { "type": 23, // ComponentType.CHECKBOX "custom_id": "like_checkbox" } } ] } } ``` ```jsonc theme={"system"} { "type": 5, // InteractionType.MODAL_SUBMIT ...additionalInteractionFields, // See the Interaction documentation for all fields "data": { "custom_id": "secret_note_modal", "components": [ { "id": 1, "type": 18, // ComponentType.LABEL "component": { "custom_id": "like_checkbox", "id": 2, "type": 23, // ComponentType.CHECKBOX "value": true } } ] } } ``` *** ## Unfurled Media Item An Unfurled Media Item is a piece of media, represented by a URL, that is used within a component. It can be constructed via either uploading media to Discord, or by referencing external media via **a direct link** to the asset. While the structure below is the full representation of an Unfurled Media Item, **only the `url` field is settable by developers** when making requests that utilize this structure. All other fields will be automatically populated by Discord. ###### Unfurled Media Item Structure | Field | Type | Description | | ------------------------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | url | string | Supports arbitrary urls and `attachment://` references | | proxy\_url? \* | string | The proxied url of the media item | | height? \* | ?integer | The height of the media item (if image or video) | | width? \* | ?integer | The width of the media item (if image or video) | | placeholder? \* | string | [Thumbhash](https://evanw.github.io/thumbhash/) placeholder (if image or video) | | placeholder\_version? \* | integer | Version of the placeholder (if image or video) | | content\_type? \* | string | The [media type](https://en.wikipedia.org/wiki/Media_type) of the content | | flags? \* | integer | [Unfurled media item flags](/developers/components/reference#unfurled-media-item-unfurled-media-item-flags) combined as a [bitfield](https://en.wikipedia.org/wiki/Bit_field) | | attachment\_id? \* \*\* | snowflake | The id of the uploaded attachment | \* This field is ignored and provided by the API as part of the response. \*\* Only present if the media item was uploaded as an attachment. ###### Unfurled Media Item Flags | Flag | Value | Description | | ------------ | -------- | ---------------------- | | IS\_ANIMATED | `1 << 0` | This image is animated | ### Uploading a file To upload a file with your message, you'll need to send your payload as `multipart/form-data` (rather than `application/json`) and include your file with a valid filename in your payload. Details and examples for uploading files can be found in the [API Reference](/developers/reference#uploading-files). ## Legacy Message Component Behavior Before the introduction of the `IS_COMPONENTS_V2` flag ([see changelog](/developers/change-log#introducing-new-components-for-messages)), message components were sent in conjunction with message content. This means that you could send a message using a subset of the available components without setting the `IS_COMPONENTS_V2` flag, and the components would be included in the message content along with `content` and `embeds`. Additionally, components of messages preceding components V2 will contain an `id` of `0`. Apps using this Legacy Message Component behavior will continue to work as expected, but it is recommended to use the new `IS_COMPONENTS_V2` flag for new apps or features as they offer more options for layout and customization. Legacy messages allow up to 5 action rows as top-level components Legacy Message Component Example ```jsonc theme={"system"} { "content": "This is a message with legacy components", "components": [ { "type": 1, "components": [ { "type": 2, "style": 1, "label": "Click Me", "custom_id": "click_me_1" } ] } ] } ``` # Using Message Components Source: https://docs.discord.com/developers/components/using-message-components Learn how to send interactive message components. ## Overview Message components are a powerful way to add interactivity to your messages. They allow you to create rich, interactive experiences for your users, making it easier for them to engage with your content. If you are sending components as part of a [webhook](/developers/resources/webhook) you'll need to use the [`?with_components=true`](/developers/resources/webhook#execute-webhook-query-string-params) query param otherwise they'll be ignored. ### Prerequisites * You must have a Discord account and be a member of the Discord Developer Portal. * You must have a Discord application created in the Discord Developer Portal. * You must have the necessary permissions to send messages in the channel where you want to use components. *** ## Sending a Message with a Component To send a message with a component, you need to set the `IS_COMPONENTS_V2` flag (`1<<15`) in your message's `flags` field. This can be done when using [Message Create](/developers/resources/message#create-message), [Execute Webhook](/developers/resources/webhook#execute-webhook), or [responding to an interaction](/developers/interactions/receiving-and-responding#create-followup-message). Setting the `IS_COMPONENTS_V2` message flag cannot be reverted: once the message has been sent, the flag cannot be removed from the message when editing the message. This flag indicates that the message contains components and disables traditional content and embeds. All content must be sent as components instead of using the standard message format. ```json theme={"system"} { "flags": 32768, "components": [ { "type": 10, "content": "This is a message using the Text Display component" } ] } ``` ## Sending a Message with Multiple Components To send a message with multiple components, you can include multiple component objects in your message's `components` field. This field allows you to specify an array of components that will be included in the message. ```json theme={"system"} { "flags": 32768, "components": [ { "type": 10, "content": "This is a Text Display component." }, { "type": 10, "content": "This is another Text Display component!" } ] } ``` ## Nesting Components with Layout Components You can also nest components within layout components. This gives you more flexibility in displaying information, images, and interactive components to your users. Check out the [list of components](/developers/components/reference#component-object-component-types) for a complete list of available layout components. For example, you can create a message with an Action Row component that contains multiple Button components. ```json theme={"system"} { "flags": 32768, "components": [ { "type": 10, "content": "This is a message with v2 components" }, { "type": 1, "components": [ { "type": 2, "style": 1, "label": "Click Me", "custom_id": "click_me_1" }, { "type": 2, "style": 2, "label": "Click Me Too", "custom_id": "click_me_2" } ] } ] } ``` ## Using Message Components with Interactions When a user interacts with an interactive message component, your app will [receive an interaction event](/developers/interactions/overview). This event contains information about the interaction, including the type of interaction and the component that was interacted with. See the [list of supported component types](/developers/components/reference#component-object-component-types) for a list of interactive message components and their interaction event payloads. You can use this information to respond to the interaction, update the message, or perform other actions, such as displaying a modal based on the user's input. Check out the [Interactions documentation](/developers/interactions/overview) for more information on handling interactions and responding to user input from interactive components. # Using Modal Components Source: https://docs.discord.com/developers/components/using-modal-components Guide to creating and displaying modal dialogs with text input fields. ## Overview Modal components are a great way to collect freeform information from your users. ### Prerequisites * You must have a Discord account and be a member of the Discord Developer Portal. * You must have a Discord application created in the Discord Developer Portal. *** ## Displaying a Modal Displaying a modal can be done in response to an [interaction](/developers/interactions/receiving-and-responding). When displaying a modal you'll use an [interaction response](/developers/interactions/receiving-and-responding#interaction-response-object) with the [`MODAL`](/developers/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type) interaction callback type and [modal fields](/developers/interactions/receiving-and-responding#interaction-response-object-modal). An example of a modal with a [String Select](/developers/components/reference#string-select) and [Text Input](/developers/components/reference#text-input) both wrapped in [Labels](/developers/components/reference#label): ```json theme={"system"} { "type": 9, "data": { "custom_id": "bug_modal", "title": "Bug Report", "components": [ { "type": 18, "label": "What's your favorite bug?", "component": { "type": 3, "custom_id": "bug_string_select", "placeholder": "Choose...", "options": [ { "label": "Ant", "value": "ant", "description": "(best option)", "emoji": { "name": "🐜" } }, { "label": "Butterfly", "value": "butterfly", "emoji": { "name": "🦋" } }, { "label": "Caterpillar", "value": "caterpillar", "emoji": { "name": "🐛" } } ] } }, { "type": 18, "label": "Why is it your favorite?", "description": "Please provide as much detail as possible!", "component": { "type": 4, "custom_id": "bug_explanation", "style": 2, "min_length": 1000, "max_length": 4000, "placeholder": "Write your explanation here...", "required": true } } ] } } ``` Example of an Action Row with three buttons # Community Resources Source: https://docs.discord.com/developers/developer-tools/community-resources Discover community-built libraries, tools, and resources for Discord development. Our community members create amazing tools and resources that help developers build and maintain their apps. From permissions calculators and embed visualizers to comprehensive libraries for interfacing with our API, our community has built a wealth of resources to make your development process smoother and more efficient. ## Discord Developers The [Official Discord Developers server](https://discord.gg/discord-developers) is a developer ran, but community driven, support hub. If you need help with developing something on Discord or want official updates from the developers, this is the place to be. ## Libraries Discord does not maintain official SDKs. The following table is an inexhaustive list of third-party libraries that have valid rate limit implementations, are recently maintained, and have large communities of active bots. ###### Discord Libraries | Name | Language | | ------------------------------------------------------------- | ---------- | | [Concord](https://github.com/Cogmasters/concord) | C | | [Discord.Net](https://github.com/discord-net/Discord.Net) | C# | | [DSharpPlus](https://github.com/DSharpPlus/DSharpPlus) | C# | | [D++](https://github.com/brainboxdotcc/DPP) | C++ | | [discljord](https://github.com/discljord/discljord) | Clojure | | [DiscordGo](https://github.com/bwmarrin/discordgo) | Go | | [Discord4J](https://github.com/Discord4J/Discord4J) | Java | | [JDA](https://github.com/DV8FromTheWorld/JDA) | Java | | [discord.js](https://github.com/discordjs/discord.js) | JavaScript | | [Eris](https://github.com/abalabahaha/eris) | JavaScript | | [Oceanic](https://github.com/OceanicJS/Oceanic) | JavaScript | | [Discordia](https://github.com/SinisterRectus/Discordia) | Lua | | [DiscordPHP](https://github.com/discord-php/DiscordPHP) | PHP | | [discord.py](https://github.com/Rapptz/discord.py) | Python | | [disnake](https://github.com/DisnakeDev/disnake) | Python | | [hikari](https://github.com/hikari-py/hikari) | Python | | [interactions.py](https://github.com/interactions-py/library) | Python | | [nextcord](https://github.com/nextcord/nextcord) | Python | | [pycord](https://github.com/Pycord-Development/pycord) | Python | | [discordrb](https://github.com/shardlab/discordrb) | Ruby | | [Serenity](https://github.com/serenity-rs/serenity) | Rust | ## Interactions [Interactions](/developers/interactions/receiving-and-responding) are the great, new way of making a Discord bot. The following open-source libraries provide help for the security and authentication checks that are mandatory if you are receiving Interactions via outgoing webhook. They also include some types for the Interactions data models. * C# * [Discord.Net.Rest](https://github.com/discord-net/Discord.Net) * [DSharpPlus.Http.AspNetCore](https://github.com/DSharpPlus/DSharpPlus) * Clojure * [ring-discord-auth](https://github.com/JohnnyJayJay/ring-discord-auth) * Dart * [nyxx\_interactions](https://github.com/l7ssha/Nyxx) * Go * [tempest](https://github.com/amatsagu/tempest) * Javascript * [discord-interactions-js](https://github.com/discord/discord-interactions-js) * [discord-slash-commands](https://github.com/MeguminSama/discord-slash-commands) and its [Deno fork](https://deno.land/x/discord_slash_commands) * [slash-create](https://github.com/Snazzah/slash-create) * Python * [discord-interactions-python](https://github.com/discord/discord-interactions-python) * [discord-interactions.py](https://github.com/LiBa001/discord-interactions.py) * [dispike](https://github.com/ms7m/dispike) * [flask-discord-interactions](https://github.com/breqdev/flask-discord-interactions) * PHP * [discord-interactions-php](https://github.com/discord/discord-interactions-php) * Other * [caddy-discord-interactions-verifier](https://github.com/CarsonHoffman/caddy-discord-interactions-verifier) * [BotForge's Application Commands Builder & Previewer](https://tools.botforge.org/appbuilder) * [Bsati's Slash Command Builder](https://bsati.github.io/dc-app-command-builder/) ## OpenAPI Specification The OpenAPI spec is currently in public preview and **is subject to breaking changes** The public preview of the [Discord HTTP API specification](https://github.com/discord/discord-api-spec) provides a standard [OpenAPI 3.1 spec](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md) for the HTTP API. ## Permission Calculators [Permissions](/developers/topics/permissions) in Discord are tricky. Luckily, we've got really smart people who love us and have made some great permissions calculators. If you're making a bot for others, and you're not sure how to properly calculate permissions or generate your [authorization URL](/developers/topics/oauth2#bot-authorization-flow), these are great tools: * [BotForge's Permissions Calculator](https://tools.botforge.org/permissions) * [FiniteReality's Permissions Calculator](https://finitereality.github.io/permissions-calculator/?v=0) * [abalabahaha's Permissions Calculator](https://discordapi.com/permissions.html#0) ## Intent Calculators [Gateway Intents](/developers/events/gateway#gateway-intents) are pretty confusing at first. If you're not sure what to send in your [Identify payload](/developers/events/gateway-events#identify), then these tools may be of help: * [ziad87's Intent Calculator](https://ziad87.net/intents/) * [Larko's Intent Calculator](https://discord-intents-calculator.vercel.app/) ## Embed Visualizers Webhooks and embeds might seem like black magic. That's because they are, but let us help you demystify them a bit. These tools can help you test how embeds will appear inside of Discord: * [JohnyTheCarrot's Embed Previewer](https://github.com/JohnyTheCarrot/discord-embed-previewer) (Browser Extension) * [AshMW's Embed Previewer](https://embedl.ink) (Embed HTML Generation) ## API Types If you're working on a project that interacts with our API, you might find an API types module useful as it provides type inspection/completion for the Discord API. | Name | Language | | ------------------------------------------------------------------- | ---------- | | [dasgo](https://github.com/switchupcb/dasgo) | Go | | [discord-api-types](https://github.com/discordjs/discord-api-types) | JavaScript | ## Game SDK Tools Discord Game SDK's lobby and networking layer shares similarities with other gaming platforms (i.e. Valve's Steamworks SDK). The following open source library provides developers a uniform interface for these shared features and can simplify developing for multiple platforms. Note: this library is tailored for Unity3D development. * [HouraiNetworking](https://github.com/HouraiTeahouse/HouraiNetworking) # Embedded App SDK Reference Source: https://docs.discord.com/developers/developer-tools/embedded-app-sdk The Embedded App SDK handles making RPC calls between your application and Discord. It is designed to assist developers in developing interactive Activities like games. To learn more about building Activities, check out our [Building an Activity](/developers/activities/building-an-activity) tutorial or explore our [Sample Projects](/developers/activities/overview#sample-projects). *** ## Install the SDK The Embedded App SDK is available via **[npm](https://www.npmjs.com/package/@discord/embedded-app-sdk)** and **[GitHub](https://github.com/discord/embedded-app-sdk)**. In your frontend JavaScript project directory, install using your package manager of choice. ``` npm install @discord/embedded-app-sdk ``` After installing, you can import and instantiate the SDK in your project. ```javascript theme={"system"} import { DiscordSDK } from "@discord/embedded-app-sdk"; const discordSdk = new DiscordSDK(DISCORD_CLIENT_ID); ``` *** ## SDK Methods | Name | Description | | ----------------------------------------------------------------------- | ----------------------------------------------------------------------- | | [ready](/developers/developer-tools/embedded-app-sdk#ready) | Resolves when your app has successfully connected to the Discord client | | [subscribe](/developers/developer-tools/embedded-app-sdk#subscribe) | Subscribe to an Embedded App SDK Event | | [unsubscribe](/developers/developer-tools/embedded-app-sdk#unsubscribe) | Unsubscribe to an Embedded App SDK Event | | [close](/developers/developer-tools/embedded-app-sdk#close) | Close an Embedded App | ### ready() Resolves when your app has successfully connected to the Discord client. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature ready(): Promise\ #### SDK Usage ```js theme={"system"} async function setup() { await discordSdk.ready(); // The rest of your app logic } ``` *** ### subscribe() Used to subscribe to a specific event from the list of [SDK Events](/developers/developer-tools/embedded-app-sdk#sdk-events). #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes Depends on the event. Refer to the Required Scopes for the specific event you are subscribing to. #### Signature subscribe\(event: [Event](/developers/developer-tools/embedded-app-sdk#sdk-events), listener: (data: EventPayloadData\) => void, ...subscribeArgs: Partial\>): Promise\<[EventEmitter](https://nodejs.org/docs/latest/api/events.html)> #### Usage ```js theme={"system"} await discordSdk.subscribe("SDK_EVENT_NAME", eventHandler, args); ``` *** ### unsubscribe() Used to unsubscribe to [SDK Events](/developers/developer-tools/embedded-app-sdk#sdk-events) that your app has already subscribed to. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature *The `EventPayloadData` will vary based on the event you are unsubscribing from. See the specific [event](/developers/developer-tools/embedded-app-sdk#sdk-events) for details.* unsubscribe\(event: [Event](/developers/developer-tools/embedded-app-sdk#sdk-events), listener: (data: EventPayloadData\) => void, ...subscribeArgs: Partial\>): Promise\<[EventEmitter](https://nodejs.org/docs/latest/api/events.html)> #### Usage ```js theme={"system"} await discordSdk.unsubscribe("SDK_EVENT_NAME"); ``` *** ### close() Used to close your app with a specified code and reason. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature close(code: [RPCCloseCodes](/developers/developer-tools/embedded-app-sdk#rpcclosecodes), message: string): void #### SDK Usage ```js theme={"system"} discordSdk.close(RPCCloseCodes.CLOSE_NORMAL, "You exited from app"); ``` *** ## SDK Commands Developers can use these commands to interact with the Discord client. The following SDK commands are prefixed with `.commands`, such as, `discordSDK.commands.authenticate`. | Name | Description | | ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [authenticate](/developers/developer-tools/embedded-app-sdk#authenticate) | Authenticate an existing client with your app | | [authorize](/developers/developer-tools/embedded-app-sdk#authorize) | Authorize a new client with your app | | [captureLog](/developers/developer-tools/embedded-app-sdk#capturelog) | Forward logs to your own logger | | [encourageHardwareAcceleration](/developers/developer-tools/embedded-app-sdk#encouragehardwareacceleration) | Presents a modal dialog to allow enabling of hardware acceleration | | [getChannel](/developers/developer-tools/embedded-app-sdk#getchannel) | Returns information about the channel, per the channel\_id | | [getChannelPermissions](/developers/developer-tools/embedded-app-sdk#getchannelpermissions) | Returns permissions for the current user in the currently connected channel | | [getEntitlements](/developers/developer-tools/embedded-app-sdk#getentitlements) | Returns a list of entitlements for the current user | | [getInstanceConnectedParticipants](/developers/developer-tools/embedded-app-sdk#getinstanceconnectedparticipants) | Returns all participants connected to the instance | | [getPlatformBehaviors](/developers/developer-tools/embedded-app-sdk#getplatformbehaviors) | Returns information about supported platform behaviors | | [getRelationships](/developers/developer-tools/embedded-app-sdk#getrelationships) | Allows your app to access a user’s Discord Friends list, their pending requests, and blocked users. This scope is part of our Social SDK - [submit for access here](https://discord.com/developers/applications/select/social-sdk/getting-started). [Social SDK Terms apply](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms), including Section 5(a)(ii) to the data you obtain | | [getSkus](/developers/developer-tools/embedded-app-sdk#getskus) | Returns a list of your app's SKUs | | [initiateImageUpload](/developers/developer-tools/embedded-app-sdk#initiateimageupload) | Presents the file upload flow in the Discord client | | [openExternalLink](/developers/developer-tools/embedded-app-sdk#openexternallink) | Allows for opening an external link from within the Discord client | | [openInviteDialog](/developers/developer-tools/embedded-app-sdk#openinvitedialog) | Presents a modal dialog with Channel Invite UI without requiring additional OAuth scopes | | [openShareMomentDialog](/developers/developer-tools/embedded-app-sdk#opensharemomentdialog) | Presents a modal dialog to share media to a channel or DM | | [setActivity](/developers/developer-tools/embedded-app-sdk#setactivity) | Modifies how your activity's rich presence is displayed in the Discord client | | [setConfig](/developers/developer-tools/embedded-app-sdk#setconfig) | Set whether or not the PIP (picture-in-picture) is interactive | | [setOrientationLockState](/developers/developer-tools/embedded-app-sdk#setorientationlockstate) | Set options for orientation and picture-in-picture (PIP) modes | | [shareLink](/developers/developer-tools/embedded-app-sdk#sharelink) | Presents a modal for the user to share a link to your activity with custom query params | | [startPurchase](/developers/developer-tools/embedded-app-sdk#startpurchase) | Launches the purchase flow for a specific SKU, per the sku\_id | | [userSettingsGetLocale](/developers/developer-tools/embedded-app-sdk#usersettingsgetlocale) | Returns the current user's locale | ### authenticate() Authenticate an existing client with your app. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature authenticate(args: [AuthenticateRequest](/developers/developer-tools/embedded-app-sdk#authenticaterequest)): Promise\<[AuthenticateResponse](/developers/developer-tools/embedded-app-sdk#authenticateresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.authenticate({ access_token: 'ACCESS_TOKEN_STRING' }); ``` *** ### authorize() Authorize a new client with your app. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature authorize(args: [AuthorizeRequest](/developers/developer-tools/embedded-app-sdk#authorizerequest)): Promise\<[AuthorizeResponse](/developers/developer-tools/embedded-app-sdk#authorizeresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.authorize({ client_id: DISCORD_CLIENT_ID, response_type: "code", state: "", prompt: "none", scope: [ // "applications.builds.upload", // "applications.builds.read", // "applications.store.update", // "applications.entitlements", // "bot", "identify", // "connections", // "email", // "gdm.join", "guilds", // "guilds.join", // "guilds.members.read", // "messages.read", // "relationships.read", // 'rpc.activities.write', // "rpc.notifications.read", // "rpc.voice.write", // "rpc.voice.read", // "webhook.incoming", ], }); ``` *** ### captureLog() Forward logs to your own logger. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature captureLog(args: [CaptureLogRequest](/developers/developer-tools/embedded-app-sdk#capturelogrequest)): Promise\ #### Usage ```js theme={"system"} await discordSdk.commands.captureLog({ level: 'log', message: 'This is my log message!' }); ``` *** ### encourageHardwareAcceleration() Presents a modal dialog to allow enabling of hardware acceleration. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ⛔️ | ⛔️ | #### Required Scopes No scopes required #### Signature encourageHardwareAcceleration(): Promise\<[EncourageHardwareAccelerationResponse](/developers/developer-tools/embedded-app-sdk#encouragehardwareaccelerationresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.encourageHardwareAcceleration(); ``` *** ### getChannel() Returns information about the channel for a provided channel ID. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes * \[guilds] for guild channels * \[guilds, dm\_channels.read] for GDM channels. dm\_channels.read requires approval from Discord. #### Signature getChannel(args: [GetChannelRequest](/developers/developer-tools/embedded-app-sdk#getchannelrequest)): Promise\<[GetChannelResponse](/developers/developer-tools/embedded-app-sdk#getchannelresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.getChannel({ channel_id: discordSdk.channelId, }); ``` *** ### getChannelPermissions() Returns permissions for the current user in the currently connected channel. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes * guilds.members.read #### Signature getChannelPermissions(): Promise\<[GetChannelPermissionsResponse](/developers/developer-tools/embedded-app-sdk#getchannelpermissionsresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.getChannelPermissions(); ``` *** ### getEntitlements() Returns a list of entitlements for the current user. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature getEntitlements(): Promise\<[GetEntitlementsResponse](/developers/developer-tools/embedded-app-sdk#getentitlementsresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.getEntitlements(); ``` *** ### getInstanceConnectedParticipants() Returns all participants connected to the instance. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature getInstanceConnectedParticipants(): Promise\<[GetInstanceConnectedParticipantsResponse](/developers/developer-tools/embedded-app-sdk#getinstanceconnectedparticipantsresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.getInstanceConnectedParticipants(); ``` *** ### getPlatformBehaviors() Returns information about supported platform behaviors. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature getPlatformBehaviors(): Promise\<[GetPlatformBehaviorsResponse](/developers/developer-tools/embedded-app-sdk#getplatformbehaviorsresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.getPlatformBehaviors(); ``` *** ### getRelationships() Returns the current user's relationships. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes * relationships.read This scope is part of our Social SDK - [submit for access here](https://discord.com/developers/applications/select/social-sdk/getting-started). [Social SDK Terms apply](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms), including Section 5(a)(ii) to the data you obtain #### Signature getRelationships(): Promise\<[GetRelationshipsResponse](/developers/developer-tools/embedded-app-sdk#getrelationshipsresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.getRelationships(); ``` *** ### getSkus() Returns a list of SKU objects. SKUs without prices are automatically filtered out. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature getSkus(): Promise\<[GetSkusResponse](/developers/developer-tools/embedded-app-sdk#getskusresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.getSkus(); ``` *** ### initiateImageUpload() Presents the file upload flow in the Discord client. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature initiateImageUpload(): Promise\<[InitiateImageUploadResponse](/developers/developer-tools/embedded-app-sdk#initiateimageuploadresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.initiateImageUpload(); ``` *** ### openExternalLink() Allows for opening an external link from within the Discord client. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature openExternalLink(args: [OpenExternalLinkRequest](/developers/developer-tools/embedded-app-sdk#openexternallinkrequest)): Promise\<[OpenExternalLinkResponse](/developers/developer-tools/embedded-app-sdk#openexternallinkresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.openExternalLink({ url: 'string url' }); ``` *** ### openInviteDialog() Presents a modal dialog with Channel Invite UI without requiring additional OAuth scopes. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature openInviteDialog(): Promise\ #### Usage ```js theme={"system"} await discordSdk.commands.openInviteDialog(); ``` *** ### openShareMomentDialog() Presents a modal dialog to share media to a channel or direct message. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ⛔️ | ⛔️ | #### Required Scopes No scopes required #### Signature openShareMomentDialog(args: [OpenShareMomentDialogRequest](/developers/developer-tools/embedded-app-sdk#opensharemomentdialogrequest)) Promise\ #### Usage ```js theme={"system"} await discordSdk.commands.openShareMomentDialog({ mediaUrl: 'DISCORD_CDN_URL' }); ``` *** ### setActivity() Modifies how your Activity's Rich Presence data is displayed in the Discord client. The inner `activity` field is a partial [Activity object](/developers/events/gateway-events#activity-object-activity-structure). Read the guide on [Using Rich Presence with the Embedded App SDK](/developers/rich-presence/using-with-the-embedded-app-sdk) for more usage details. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes * rpc.activities.write #### Signature setActivity(args: [SetActivityRequest](/developers/developer-tools/embedded-app-sdk#setactivityrequest)): Promise\<[Activity](/developers/developer-tools/embedded-app-sdk#activity)> #### Usage ```js theme={"system"} await discordSdk.commands.setActivity({ activity: { type: 0, details: 'Details', state: 'Playing' } }); ``` *** ### setConfig() Set whether or not the PIP (picture-in-picture) is interactive. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ⛔️ | ⛔️ | #### Required Scopes No scopes required #### Signature setConfig(args: [SetConfigRequest](/developers/developer-tools/embedded-app-sdk#setconfigrequest)): Promise\<[SetConfigResponse](/developers/developer-tools/embedded-app-sdk#setconfigresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.setConfig({ use_interactive_pip: true }) ``` *** ### setOrientationLockState() Locks the application to specific orientations in each of the supported layout modes. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ⛔️ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature setOrientationLockState(args: [SetOrientationLockStateRequest](/developers/developer-tools/embedded-app-sdk#setorientationlockstaterequest)): Promise\ #### Usage ```js theme={"system"} import {Common} from '@discord/embedded-app-sdk'; await discordSdk.commands.setOrientationLockState({ lock_state: Common.OrientationLockStateTypeObject.LANDSCAPE, picture_in_picture_lock_state: Common.OrientationLockStateTypeObject.LANDSCAPE, grid_lock_state: Common.OrientationLockStateTypeObject.UNLOCKED }); ``` *** ### shareLink() Presents the user with a modal to share a link #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes No scopes required #### Signature shareLink(args: [ShareLinkRequest](/developers/developer-tools/embedded-app-sdk#sharelinkrequest)): Promise\<[ShareLinkResponse](/developers/developer-tools/embedded-app-sdk#sharelinkresponse)>\ #### Usage ```js theme={"system"} const { success } = await discordSdk.commands.shareLink({ message: 'This message is shared alongside the link!', custom_id: 'some_custom_id', }); success ? console.log('User shared link!') : console.log('User did not share link!'); ``` *** ### startPurchase() Launches the purchase flow for a specific SKU ID. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ⛔️ | ⛔️ | #### Required Scopes No scopes required #### Signature startPurchase(args: [StartPurchaseRequest](/developers/developer-tools/embedded-app-sdk#startpurchaserequest)): Promise\<[StartPurchaseResponse](/developers/developer-tools/embedded-app-sdk#startpurchaseresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.startPurchase({sku_id: skuId}); ``` *** ### userSettingsGetLocale() Returns the current user's locale. #### Supported Platforms | Web | iOS | Android | | --- | --- | ------- | | ✅ | ✅ | ✅ | #### Required Scopes * identify #### Signature userSettingsGetLocale(): Promise\<[UserSettingsGetLocaleResponse](/developers/developer-tools/embedded-app-sdk#usersettingsgetlocaleresponse)> #### Usage ```js theme={"system"} await discordSdk.commands.userSettingsGetLocale(); ``` *** ## SDK Events Developers may use the following events alongside the `subscribe()` SDK method to subscribe to events from Discord and supported devices. | Name | Description | | --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | [READY](/developers/developer-tools/embedded-app-sdk#ready) | non-subscription event sent immediately after connecting, contains server information | | [ERROR](/developers/developer-tools/embedded-app-sdk#error) | non-subscription event sent when there is an error, including command responses | | [VOICE\_STATE\_UPDATE](/developers/developer-tools/embedded-app-sdk#voicestateupdate) | sent when a user's voice state changes in a subscribed voice channel (mute, volume, etc.) | | [SPEAKING\_START](/developers/developer-tools/embedded-app-sdk#speakingstart) | sent when a user in a subscribed voice channel speaks | | [SPEAKING\_STOP](/developers/developer-tools/embedded-app-sdk#speakingstop) | sent when a user in a subscribed voice channel stops speaking | | [ACTIVITY\_LAYOUT\_MODE\_UPDATE](/developers/developer-tools/embedded-app-sdk#activitylayoutmodeupdate) | Received when a user changes the layout mode in the Discord client | | [ORIENTATION\_UPDATE](/developers/developer-tools/embedded-app-sdk#orientationupdate) | Received when screen orientation changes | | [CURRENT\_USER\_UPDATE](/developers/developer-tools/embedded-app-sdk#currentuserupdate) | Received when the current user object changes | | [CURRENT\_GUILD\_MEMBER\_UPDATE](/developers/developer-tools/embedded-app-sdk#currentguildmemberupdate) | Received when the current guild member object changes | | [THERMAL\_STATE\_UPDATE](/developers/developer-tools/embedded-app-sdk#thermalstateupdate) | Received when Android or iOS thermal states are surfaced to the Discord app | | [ACTIVITY\_INSTANCE\_PARTICIPANTS\_UPDATE](/developers/developer-tools/embedded-app-sdk#activityinstanceparticipantsupdate) | Received when the number of instance participants changes | | [RELATIONSHIP\_UPDATE](/developers/developer-tools/embedded-app-sdk#relationshipupdate) | Received when a relationship of the current user is updated | | [ENTITLEMENT\_CREATE](/developers/developer-tools/embedded-app-sdk#entitlementcreate) | Received when an entitlement is created for a SKU | ### READY Non-subscription event sent immediately after connecting, contains server information. #### Required Scopes No scopes required #### Sample Event Payload ```javascript theme={"system"} { "v": 1, "config": { "cdn_host": "cdn.discordapp.com", "api_endpoint": "//discord.com/api", "environment": "production" } } ``` ### ERROR Non-subscription event sent when there is an error, including command responses. #### Required Scopes No scopes required #### Sample Event Payload ```javascript theme={"system"} { "code": 4006, "message": "Not authenticated or invalid scope" } ``` *** ### VOICE\_STATE\_UPDATE Received when a user's voice state changes in a subscribed voice channel (mute, volume, etc). #### Required Scopes * rpc.voice.read #### Sample Event Payload ```javascript theme={"system"} { "voice_state": { "mute": false, "deaf": false, "self_mute": false, "self_deaf": false, "suppress": false }, "user": { "id": "190320984123768832", "username": "test 2", "discriminator": "7479", "avatar": "b004ec1740a63ca06ae2e14c5cee11f3", "bot": false }, "nick": "test user 2", "volume": 110, "mute": false, "pan": { "left": 1.0, "right": 1.0 } } ``` *** ### SPEAKING\_START Received when a user in a subscribed voice channel speaks. #### Required Scopes * rpc.voice.read #### Sample Event Payload ```javascript theme={"system"} { "channel_id": "7173758092142710784", "user_id": "7173758143913005056" } ``` *** ### SPEAKING\_STOP Received when a user in a subscribed voice channel stops speaking. #### Required Scopes * rpc.voice.read #### Sample Event Payload ```javascript theme={"system"} { "channel_id": "7173758211307081728", "user_id": "7173758261412237312" } ``` *** ### ACTIVITY\_LAYOUT\_MODE\_UPDATE Received when a user changes the layout mode in the Discord client. #### Required Scopes No scopes required #### Sample Event Payload ```javascript theme={"system"} { "layout_mode": 1 } ``` *** ### ORIENTATION\_UPDATE Received when screen orientation changes. #### Required Scopes No scopes required #### Sample Event Payload ```javascript theme={"system"} { "screen_orientation": 1 } ``` *** ### CURRENT\_USER\_UPDATE Received when the current user object changes. #### Required Scopes * identify #### Sample Event Payload ```javascript theme={"system"} { "id": "7173771622812225536", "username": "beef_supreme", "discriminator": "0", "global_name": "Dis Cord", "avatar": "abcdefg", "avatar_decoration_data": { "asset": "abcdefg", "sku_id": "123456789" }, "bot": false, "flags": 1, "premium_type": 2 } ``` *** ### CURRENT\_GUILD\_MEMBER\_UPDATE Received when the current guild member object changes. #### Required Scopes * identify * guilds.members.read #### Sample Event Payload ```javascript theme={"system"} { "user_id": "7173771622812225536", "nick": "beef_supreme", "guild_id": "613425648685547541" "avatar": "abcdefg", "avatar_decoration_data": { "asset": "abcdefg", "sku_id": "123456789" }, "color_string": "#ffff00" } ``` *** ### THERMAL\_STATE\_UPDATE Received when Android or iOS thermal states are surfaced to the Discord mobile app. #### Required Scopes No scopes required #### Sample Event Payload ```javascript theme={"system"} { thermal_state: 0 } ``` *** ### ACTIVITY\_INSTANCE\_PARTICIPANTS\_UPDATE Received when the number of instance participants changes. #### Required Scopes No scopes required #### Sample Event Payload ```javascript theme={"system"} { "participants": [ { "id": "7173771622812225536", "username": "beef_supreme", "discriminator": "0", "global_name": "Dis Cord", "avatar": "abcdefg", "avatar_decoration_data": { "asset": "abcdefg", "sku_id": "123456789" }, "bot": false, "flags": 1, "premium_type": 2 } ] } ``` *** ### RELATIONSHIP\_UPDATE Received when a relationship of the current user is updated. #### Required Scopes * relationships.read This scope is part of our Social SDK - [submit for access here](https://discord.com/developers/applications/select/social-sdk/getting-started). [Social SDK Terms apply](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms), including Section 5(a)(ii) to the data you obtain #### Sample Event Payload ```javascript theme={"system"} { "type": 1, "user": { "id": "7173771622812225536", "username": "beef_supreme", "discriminator": "0", "global_name": "Dis Cord", "avatar": "abcdefg", "avatar_decoration_data": { "asset": "abcdefg", "sku_id": "123456789" }, "bot": false, "flags": 1, "premium_type": 2 } } ``` *** ### ENTITLEMENT\_CREATE Coming soon! Not available during Developer Preview ## SDK Interfaces #### Activity | Property | Type | | ---------------- | --------------------------------------------------------------------------- | | name | string | | type | number | | url? | string \| null | | created\_at? | number \| null | | timestamps? | [Timestamp](/developers/developer-tools/embedded-app-sdk#timestamp) \| null | | application\_id? | string \| null | | details? | string \| null | | details\_url? | string \| null | | state? | string \| null | | state\_url? | string \| null | | emoji? | [Emoji](/developers/developer-tools/embedded-app-sdk#emoji) \| null | | party? | [Party](/developers/developer-tools/embedded-app-sdk#party) \| null | | assets? | [Assets](/developers/developer-tools/embedded-app-sdk#assets) \| null | | secrets? | [Secrets](/developers/developer-tools/embedded-app-sdk#secrets) \| null | | instance? | boolean \| null | | flags? | number \| null | #### Assets | Property | Type | | ------------- | -------------- | | large\_image? | string \| null | | large\_text? | string \| null | | large\_url? | string \| null | | small\_image? | string \| null | | small\_text? | string \| null | | small\_url? | string \| null | #### Application | Property | Type | | ------------- | -------------- | | description | string | | icon? | string \| null | | id | string | | rpc\_origins? | string\[] | | name | string | #### Attachment | Property | Type | | ---------- | -------------- | | id | string | | filename | string | | size | number | | url | string | | proxy\_url | string | | height? | number \| null | | width? | number \| null | #### AuthenticateRequest | Property | Type | | -------------- | -------------- | | access\_token? | string \| null | #### AuthenticateResponse | Property | Type | | ------------- | ----------------------------------------------------------------------- | | access\_token | string | | user | [User](/developers/developer-tools/embedded-app-sdk#user) | | scopes | string\[] | | expires | string | | application | [Application](/developers/developer-tools/embedded-app-sdk#application) | #### AuthorizeRequest | Property | Type | | ------------------------ | -------------------------------------------------------------------------- | | client\_id | string | | scope | [OAuthScopes](/developers/developer-tools/embedded-app-sdk#oauthscopes)\[] | | response\_type? | 'code' | | code\_challenge? | string | | state? | string | | prompt? | 'none' | | code\_challenge\_method? | 'S256' | #### AuthorizeResponse | Property | Type | | -------- | ------ | | code | string | #### AvatarDecorationData | Property | Type | | -------- | -------------- | | asset | string | | sku\_id? | string \| null | #### CaptureLogRequest | Property | Type | | -------- | ------------------------------------------------------------------------- | | level | [ConsoleLevel](/developers/developer-tools/embedded-app-sdk#consolelevel) | | message | string | #### ChannelMention | Property | Type | | --------- | ------ | | id | string | | guild\_id | string | | type | number | | name | string | #### Embed | Property | Type | | ------------ | ----------------------------------------------------------------------------------- | | title? | string \| null | | type? | string \| null | | description? | string \| null | | url? | string \| null | | timestamp? | string \| null | | color? | number \| null | | footer? | [EmbedFooter](/developers/developer-tools/embedded-app-sdk#embedfooter) \| null | | image? | Image \| null | | thumbnail? | Image \| null | | video? | Video \| null | | provider? | [EmbedProvider](/developers/developer-tools/embedded-app-sdk#embedprovider) \| null | | author? | [EmbedAuthor](/developers/developer-tools/embedded-app-sdk#embedauthor) \| null | | fields? | [EmbedField](/developers/developer-tools/embedded-app-sdk#embedfield)\[] \| null | #### EmbedAuthor | Property | Type | | ----------------- | -------------- | | name? | string \| null | | url? | string \| null | | icon\_url? | string \| null | | proxy\_icon\_url? | string \| null | #### EmbedField | Property | Type | | -------- | ------- | | name | string | | value | string | | inline | boolean | #### EmbedFooter | Property | Type | | ----------------- | -------------- | | text | string | | icon\_url? | string \| null | | proxy\_icon\_url? | string \| null | #### EmbedProvider | Property | Type | | -------- | -------------- | | name? | string \| null | | url? | string \| null | #### Emoji | Property | Type | | ---------------- | ----------------------------------------------------------------- | | id | string | | name? | string \| null | | roles? | string\[] \| null | | user? | [User](/developers/developer-tools/embedded-app-sdk#user) \| null | | require\_colons? | boolean \| null | | managed? | boolean \| null | | animated? | boolean \| null | | available? | boolean \| null | #### EncourageHardwareAccelerationResponse | Property | Type | | -------- | ------- | | enabled | boolean | #### Entitlement | Property | Type | | ---------------------- | ----------------- | | id | string | | sku\_id | string | | application\_id | string | | user\_id | string | | gift\_code\_flags | number | | type | string \| number | | gifter\_user\_id? | string \| null | | branches? | string\[] \| null | | starts\_at? | string \| null | | ends\_at? | string \| null | | parent\_id? | string \| null | | consumed? | boolean \| null | | deleted? | boolean \| null | | gift\_code\_batch\_id? | string \| null | #### GetChannelPermissionsResponse | Property | Type | | ----------- | ---------------- | | permissions | bigint \| string | #### GetChannelRequest | Property | Type | | ----------- | ------ | | channel\_id | string | #### GetChannelResponse | Property | Type | | ------------- | ------------------------------------------------------------------------------------- | | id | string | | type | [ChannelTypesObject](/developers/developer-tools/embedded-app-sdk#channeltypesobject) | | guild\_id? | string \| null | | name? | string \| null | | topic? | string \| null | | bitrate? | number \| null | | user\_limit? | number \| null | | position? | number \| null | | voice\_states | [UserVoiceState](/developers/developer-tools/embedded-app-sdk#uservoicestate)\[] | | messages | [Message](/developers/developer-tools/embedded-app-sdk#message)\[] | #### GetEntitlementsResponse | Property | Type | | ------------ | -------------------------------------------------------------------------- | | entitlements | [Entitlement](/developers/developer-tools/embedded-app-sdk#entitlement)\[] | #### GetInstanceConnectedParticipantsResponse | Property | Type | | ------------ | ------------------------------------------------------------ | | participants | [User](/developers/developer-tools/embedded-app-sdk#user)\[] | #### GetPlatformBehaviorsResponse | Property | Type | | ----------------------- | ------- | | iosKeyboardResizesView? | boolean | #### GetRelationshipsResponse | Property | Type | | ------------- | ---------------------------------------------------------------------------- | | relationships | [Relationship](/developers/developer-tools/embedded-app-sdk#relationship)\[] | #### GetSkusResponse | Property | Type | | -------- | ---------------------------------------------------------- | | skus | [Sku](/developers/developer-tools/embedded-app-sdk#sku)\[] | #### GuildMember | Property | Type | | ---------- | --------------------------------------------------------- | | user | [User](/developers/developer-tools/embedded-app-sdk#user) | | nick? | string \| null | | roles | string\[] | | joined\_at | string | | deaf | boolean | | mute | boolean | #### GuildMemberRPC | Property | Type | | ------------------------- | ------------------------------------------------------------------------------------------------- | | user\_id | string | | nick? | string \| null | | guild\_id | string | | avatar? | string \| null | | avatar\_decoration\_data? | [AvatarDecorationData](/developers/developer-tools/embedded-app-sdk#avatardecorationdata) \| null | | color\_string? | string \| null | #### Image | Property | Type | | ----------- | -------------- | | url? | string \| null | | proxy\_url? | string \| null | | height? | number \| null | | width? | number \| null | #### InitiateImageUploadResponse | Property | Type | | ---------- | ------ | | image\_url | string | #### Message | Property | Type | | | -------------------- | --------------------------------------------------------------------------------------------- | -------------- | | id | string | | | channel\_id | string | | | guild\_id? | string \| null | | | author? | [User](/developers/developer-tools/embedded-app-sdk#user) \| null | | | member? | [GuildMember](/developers/developer-tools/embedded-app-sdk#guildmember) \| null | | | content | string | | | timestamp | string | | | edited\_timestamp? | string \| null | | | tts | boolean | | | mention\_everyone | boolean | | | mentions | [User](/developers/developer-tools/embedded-app-sdk#user)\[] | | | mention\_roles | string\[] | | | mention\_channels | [ChannelMention](/developers/developer-tools/embedded-app-sdk#channelmention)\[] | | | attachments | [Attachment](/developers/developer-tools/embedded-app-sdk#attachment)\[] | | | embeds | [Embed](/developers/developer-tools/embedded-app-sdk#embed)\[] | | | reactions? | [Reaction](/developers/developer-tools/embedded-app-sdk#reaction)\[] \| null | | | nonce? | string | number \| null | | pinned | boolean | | | webhook\_id? | string \| null | | | type | number | | | activity? | [MessageActivity](/developers/developer-tools/embedded-app-sdk#messageactivity) \| null | | | application? | [MessageApplication](/developers/developer-tools/embedded-app-sdk#messageapplication) \| null | | | message\_reference? | [MessageReference](/developers/developer-tools/embedded-app-sdk#messagereference) \| null | | | flags? | number | | | stickers? | Sticker\[] \| null | | | referenced\_message? | [Message](/developers/developer-tools/embedded-app-sdk#message) \| null | | #### MessageActivity | Property | Type | | ---------- | -------------- | | type | number | | party\_id? | string \| null | #### MessageApplication | Property | Type | | ------------- | -------------- | | id | string | | cover\_image? | string \| null | | description | string | | icon? | string \| null | | name | string | #### MessageReference | Property | Type | | ------------ | -------------- | | message\_id? | string \| null | | channel\_id? | string \| null | | guild\_id? | string \| null | #### OpenExternalLinkRequest | Property | Type | | -------- | ------ | | url | string | #### OpenExternalLinkResponse `{ opened: null }` is returned on Discord clients before December 2024 that do not report the open link result. | Property | Type | | -------- | --------------- | | opened | boolean \| null | #### OpenShareMomentDialogRequest | Property | Type | | -------- | ------ | | mediaUrl | string | #### Party | Property | Type | | -------- | ----------------- | | id? | string \| null | | size? | number\[] \| null | #### Reaction | Property | Type | | -------- | ----------------------------------------------------------- | | count | number | | me | boolean | | emoji | [Emoji](/developers/developer-tools/embedded-app-sdk#emoji) | #### Relationship | Property | Type | | -------- | ------------------------------------------------------------------------- | | type | [number](/developers/developer-tools/embedded-app-sdk#relationship-types) | | user | [User](/developers/developer-tools/embedded-app-sdk#user) | #### Secrets | Property | Type | | -------- | ------ | | join? | string | | match? | string | #### SetActivityRequest | Property | Type | | -------- | ----------------------------------------------------------------- | | activity | [Activity](/developers/developer-tools/embedded-app-sdk#activity) | #### SetConfigRequest | Property | Type | | --------------------- | ------- | | use\_interactive\_pip | boolean | #### SetConfigResponse | Property | Type | | --------------------- | ------- | | use\_interactive\_pip | boolean | #### SetOrientationLockStateRequest | Property | Type | | --------------------------------- | --------------------------------------------------------------------------------------------------- | | lock\_state | [OrientationLockState](/developers/developer-tools/embedded-app-sdk#orientationlockstatetypeobject) | | picture\_in\_picture\_lock\_state | [OrientationLockState](/developers/developer-tools/embedded-app-sdk#orientationlockstatetypeobject) | | grid\_lock\_state | [OrientationLockState](/developers/developer-tools/embedded-app-sdk#orientationlockstatetypeobject) | #### ShareLinkRequest | Property | Type | | ----------- | ------ | | custom\_id? | string | | message | string | #### ShareLinkResponse | Property | Type | | -------- | ------- | | success | boolean | #### Sku | Property | Type | | --------------- | --------------------------------------------------------------------------- | | id | string | | name | string | | type | [SkuTypeObject](/developers/developer-tools/embedded-app-sdk#skutypeobject) | | price | [SkuPrice](/developers/developer-tools/embedded-app-sdk#skuprice) | | application\_id | string | | flags | number | | release\_date | string \| null | #### SkuPrice | Property | Type | | -------- | ------ | | amount | number | | currency | string | #### StartPurchaseRequest | Property | Type | | -------- | ------ | | sku\_id | string | #### StartPurchaseResponse | Value | | ---------------------------------------------------------------------------------- | | [Entitlement](/developers/developer-tools/embedded-app-sdk#entitlement)\[] \| null | #### Timestamp | Property | Type | | -------- | ------ | | start? | number | | end? | number | #### User | Property | Type | | ------------------------ | ------------------------------------------------------------------------------------------------- | | id | string | | username | string | | discriminator | string | | global\_name? | string \| null | | avatar? | string \| null | | avatar\_decoration\_data | [AvatarDecorationData](/developers/developer-tools/embedded-app-sdk#avatardecorationdata) \| null | | bot | boolean | | flags? | number \| null | | premium\_type? | number \| null | #### UserSettingsGetLocaleResponse | Property | Type | | -------- | ------ | | locale | string | #### UserVoiceState | Property | Type | | ------------ | --------------------------------------------------------------------- | | mute | boolean | | nick | string | | user | [User](/developers/developer-tools/embedded-app-sdk#user) | | voice\_state | [VoiceState](/developers/developer-tools/embedded-app-sdk#voicestate) | | volume | number | #### Video | Property | Type | | -------- | -------------- | | url? | string \| null | | height? | number \| null | | width? | number \| null | #### VoiceState | Property | Type | | ---------- | ------- | | mute | boolean | | deaf | boolean | | self\_mute | boolean | | self\_deaf | boolean | | suppress | boolean | ## SDK Enums #### ChannelTypesObject | Name | Value | | -------------------- | ----- | | UNHANDLED | -1 | | DM | 1 | | GROUP\_DM | 3 | | GUILD\_TEXT | 0 | | GUILD\_VOICE | 2 | | GUILD\_CATEGORY | 4 | | GUILD\_ANNOUNCEMENT | 5 | | GUILD\_STORE | 6 | | ANNOUNCEMENT\_THREAD | 10 | | PUBLIC\_THREAD | 11 | | PRIVATE\_THREAD | 12 | | GUILD\_STAGE\_VOICE | 13 | | GUILD\_DIRECTORY | 14 | | GUILD\_FORUM | 15 | #### ConsoleLevel | Value | | ------- | | 'error' | | 'log' | | 'warn' | | 'debug' | | 'info' | #### OrientationLockStateTypeObject | Name | Value | | --------- | ----- | | UNHANDLED | -1 | | UNLOCKED | 1 | | PORTRAIT | 2 | | LANDSCAPE | 3 | #### ThermalStateTypeObject | Name | Value | | --------- | ----- | | UNHANDLED | -1 | | NOMINAL | 0 | | FAIR | 1 | | SERIOUS | 2 | | CRITICAL | 3 | #### OrientationTypeObject | Name | Value | | --------- | ----- | | UNHANDLED | -1 | | PORTRAIT | 0 | | LANDSCAPE | 1 | #### LayoutModeTypeObject | Name | Value | | --------- | ----- | | UNHANDLED | -1 | | FOCUSED | 0 | | PIP | 1 | | GRID | 2 | #### OAuthScopes | Value | | ---------------------------- | | 'bot' | | 'rpc' | | 'identify' | | 'connections' | | 'email' | | 'guilds' | | 'guilds.join' | | 'guilds.members.read' | | 'gdm.join' | | 'messages.read' | | 'rpc.notifications.read' | | 'rpc.voice.write' | | 'rpc.voice.read' | | 'rpc.activities.write' | | 'webhook.incoming' | | 'applications.commands' | | 'applications.builds.upload' | | 'applications.builds.read' | | 'applications.store.update' | | 'applications.entitlements' | | 'relationships.read' | | 'activities.read' | | 'activities.write' | | 'dm\_channels.read' | #### RPCCloseCodes | Name | Code | | ------------------ | ---- | | CLOSE\_NORMAL | 1000 | | CLOSE\_UNSUPPORTED | 1003 | | CLOSE\_ABNORMAL | 1006 | | INVALID\_CLIENTID | 4000 | | INVALID\_ORIGIN | 4001 | | RATELIMITED | 4002 | | TOKEN\_REVOKED | 4003 | | INVALID\_VERSION | 4004 | | INVALID\_ENCODING | 4005 | #### SkuTypeObject | Name | Value | | ------------ | ----- | | UNHANDLED | -1 | | APPLICATION | 1 | | DLC | 2 | | CONSUMABLE | 3 | | BUNDLE | 4 | | SUBSCRIPTION | 5 | #### Relationship Types | Value | Name | Description | | ----- | ---------------- | ------------------------------------------------------------------------------------------------ | | 0 | None | The user has no relationship with the other user. | | 1 | Friend | The user is friends with the other user. | | 2 | Blocked | The current user has blocked the target user. | | 3 | Pending Incoming | The current user has received a friend request from the target user, but it is not yet accepted. | | 4 | Pending Outgoing | The current user has sent a friend request to the target user, but it is not yet accepted. | | 5 | Implicit | The Implicit type is documented for visibility, but should be unused in the SDK. | | 6 | Suggestion | The Suggestion type is documented for visibility, but should be unused in the SDK. | # Social SDK Core Concepts Source: https://docs.discord.com/developers/discord-social-sdk/core-concepts Overview of the Discord Social SDK's core concepts including features, communication, and platform compatibility. The Discord Social SDK allows you to build social features into your game, including friend lists, messaging, voice chat, and rich presence. Unlike a traditional SDK with built-in UI components, the Discord Social SDK provides access to raw data, allowing developers to create a fully customized experience that aligns with their game's aesthetic. ## Core Concepts Overview Select a topic below to learn more about the Discord Social SDK: }> Explore social features like account linking, friends, and rich presence. }> Learn about messaging, voice chat, and in-game lobbies. }> Learn about the integration overview and implementation steps. }> See supported platforms and download information. }> Understand OAuth2 scopes and client types for authentication. *** ## Next Steps After exploring these core concepts, you can start implementing the Discord Social SDK in your game: * **Ready to integrate?** Follow our [Getting Started](/developers/discord-social-sdk/getting-started) guide for step-by-step setup instructions. * **Need implementation details?** Check out the development guides for specific features like [Account Linking](/developers/discord-social-sdk/development-guides/account-linking-with-discord) and [Managing Lobbies](/developers/discord-social-sdk/development-guides/managing-lobbies). * **Looking for UI guidance?** Review the [Design Principles](/developers/discord-social-sdk/design-guidelines/principles) for best practices. *** ## Change Log | Date | Changes | | -------------- | ------------------------- | | July 21, 2025 | restructure core concepts | | June 30, 2025 | restructure oauth scopes | | March 17, 2025 | initial release | # Communication Features Source: https://docs.discord.com/developers/discord-social-sdk/core-concepts/communication-features Learn about Discord Social SDK's communication features including direct messages and voice chat. The Discord Social SDK provides powerful communication features to enhance player interaction in your game. These features include messaging, voice chat, and in-game lobbies, allowing players to connect seamlessly. The following communication features are available for development and testing, but their usage is capped with a rate limit. For more information about current rate limits for communication features, please see [Rate Limits](/developers/discord-social-sdk/core-concepts/communication-features#rate-limits), and see the [Applying for Increased Rate Limits for Production Releases](/developers/discord-social-sdk/core-concepts/communication-features#applying-for-increased-rate-limits-for-production-releases) section below for how to increase those rate limits, such that you can use these features for full release. ## Messaging & Communication Users can communicate via direct messages (DMs) and voice calls: * DMs: One-on-one private chat ([`MessageHandle`]). * Calls: Real-time voice communication inside a game lobby ([`Call`]). | Development Guides | | ---------------------------------------------------------------------------------------------------- | | [Sending Direct Messages](/developers/discord-social-sdk/development-guides/sending-direct-messages) | | [Managing Voice Chat](/developers/discord-social-sdk/development-guides/managing-voice-chat) | | Design Guidelines | | ----------------------------------------------------------------------------------- | | [Direct Messages](/developers/discord-social-sdk/design-guidelines/direct-messages) | ## Lobbies & In-Game Chat A lobby is a virtual space where players can interact through voice and text chat. * Your game controls lobbies, which can have different membership rules. * Integrated voice chat allows real-time communication among players in a session. | Development Guides | | ------------------------------------------------------------------------------------- | | [Manging Lobbies](/developers/discord-social-sdk/development-guides/managing-lobbies) | ## Linked Channels Games can link in-game chat with Discord's server-based text channels in their UI, allowing players to chat in a Discord server without leaving the game. | Development Guides | | ------------------------------------------------------------------------------------ | | [Linked channels](/developers/discord-social-sdk/development-guides/linked-channels) | | Design Guidelines | | ----------------------------------------------------------------------------------- | | [Linked channels](/developers/discord-social-sdk/design-guidelines/linked-channels) | *** ## Development Rate Limits Prior to successful approval to increase rate limits, communication features have the following restrictions: * **Lobby Create/Join operations:** 100 requests every 2 hours. * **Lobby Update operations:** 100 requests every 2 hours. * This includes adding/removing members, updating metadata, and creating Discord server invites for linked channels. * **Lobby Linking operations:** 20 requests every 2 hours. * This includes creating or deleting a linked channel * **Sending Messages to Lobby operations:** 100 requests every 2 hours * **Sending Direct Message operations:** 100 requests every 2 hours. These are per-application rate limits, not per-user. These limitations are designed to provide sufficient capacity for development, testing, and small-scale demos while ensuring system stability. Once you gain full access through the rate limit increase application process, these restrictions are increased, allowing your game to scale to production levels. ## Applying for Increased Rate Limits for Production Releases To apply for increased rate limits on Discord Social SDK communication features, you must meet the requirements outlined in the [Application Requirements for Increased Rate Limits](/developers/discord-social-sdk/core-concepts/communication-features#application-requirements-for-increased-rate-limits) section below. Once you have met those requirements, you can apply for increased rate limits by following these steps: 1. Open the [Application page of the Developer Portal](https://discord.com/developers/applications) 2. Open the Application you want to apply for rate limit increase 3. Under the **Discord Social SDK** heading in the sidebar, click the [**Comms Access**](https://discord.com/developers/applications/select/social-sdk/comms-access) button 4. Fill out the application form with the required information and supporting materials Video capture provided to the application should be in url format, hosted on a file or video-sharing service of your choice as an unlisted video ## Application Requirements for Increased Rate Limits This section outlines the specific requirements you must meet before submitting your game for approval to unlock Discord Social SDK text and/or voice communications for full release. You'll find: 1. **Minimum required feature set:** Your game must have integrated core Discord Social SDK features, such as Discord Account Linking, Rich Presence with Discord Joins, and Full Access to Discord Friends. 2. **Feature Functionality:** The Discord Social SDK features you choose to integrate in your game must have end-to-end functionality, meaning that all your user interactions can be completed, work as intended across both game and Discord clients, and resolve negative options (such as user denial of options and failure states) correctly. 3. **Feature Access and Conveyance:** Discord Social SDK integrations must include the option for users to link their Discord account, and make it accessible and easily understandable for players to activate. 4. **Supporting Materials:** You’ll be required to provide specific documentation of your game for review, such as a capture of integration and development timeline. 5. **Age-restricted user protection:** You’ll need to confirm that you have appropriate measures in place for players’ access to the SDK features in your game, depending on their age. These requirements detail the **minimum bar** to be eligible for Social SDK communications usage at scale. Check out our [design guidelines](/developers/discord-social-sdk/design-guidelines) for what **“great”** looks like. Great integrations can drive higher player engagement and retention by creating seamless social experiences that keep players connected and coming back to your game. And of course, remember to make sure you are complying with our [Social SDK Terms](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms).

If you believe you meet these requirements, you can [apply for access to full release comms features](/developers/discord-social-sdk/core-concepts/communication-features#applying-for-increased-rate-limits-for-production-releases). Discord may approve or deny your access after review of your application and additional terms may apply.
### Minimum Required Feature Set **In order to unlock Discord text and/or voice communications for full release, integrations of the Social SDK must include the following features at a minimum**. Developers are of course welcome (and encouraged) to take advantage of any SDK features that will supercharge their games beyond these minimum requirements. Exception: Prohibited Off-Platform Interactions by Sony
For integrations experienced on Sony Platforms (e.g. PlayStation 5)…

1. **Do not allow access to Account Linking** entry points.
2. **Do not allow access to Linked Channels**.
3. **Limit messaging and Invites to other players currently playing** the game.
4. **Do not display off-platform presence and logos** (including Discord).
Required features are… #### Option for Discord Account Linking **Players must have the opportunity to [link their Discord account in-game](/developers/discord-social-sdk/design-guidelines/signing-in).** This ensures players can access the full Social SDK-powered experience, and connects your game to a player’s existing social network. #### Rich Presence and Discord Joins **Discord Users must be able to see [Rich Presence](/developers/discord-social-sdk/design-guidelines/status-rich-presence) updates for Discord-linked player accounts and join their game via Ask to Join.** This feature drives organic discovery and social engagement by showing friends what players are doing and creating opportunities for spontaneous social interaction and game sessions. #### Full Access to Discord Friends **Account-linked players must have their Discord friends accessible to them in-game, with supporting UI to take actions like [messaging](/developers/discord-social-sdk/design-guidelines/direct-messages), inviting, blocking, and ignoring**. This can be accomplished as a [Unified Friends List](/developers/discord-social-sdk/design-guidelines/unified-friends-list) which shows status across platforms, or as a simple in-game Discord friends list. Games should never copy and store Discord friend information (i.e. a player unlinking their Discord account should automatically remove Discord friend information in-game). ### Feature Functionality **All integrated Social SDK features (whether required as a part of the minimum feature set or not) must have at a minimum base level functionality for their intended use.** This is a **separate requirement in addition to the minimum feature set** above. “Base level functionality” means that each integrated feature’s **end-to-end user flow is** **completable** and **resolves negative options** (user denial of options and failure states) correctly. Details for each feature are as follows: #### Discord Account Linking **Intended Use:** Connect a player's game account with their Discord account to enable social features and cross-platform functionality. **Example Complete User Flow:** 1. Player encounters sign-in prompt (at game start, friends list access, or feature interaction) 2. Player clicks Discord sign-in button 3. Authorization flow launches (Overlay > Discord Client > Browser fallback) 4. Player completes OAuth authorization on Discord 5. Game receives authorization confirmation 6. Success state displays in-game confirming connection 7. Social features become available and populate with Discord data **Negative Options to Resolve:** * **User declines authorization:** Return to game normally with a provisional account; maintain access to sign-in option * **Authorization fails/times out:** Show clear error message with retry option * **User wants to disconnect:** Provide deauthorization option in-game and maintain game functionality post-disconnect These requirements represent the minimum standards for functionality. To create an even better player experience, see our [Design Guidelines for Signing In](/developers/discord-social-sdk/design-guidelines/signing-in). #### Rich Presence **Intended Use:** Display detailed, real-time information about a player's in-game activity on their Discord profile, allowing friends to see what they're doing and potentially join their session. **Example Complete User Flow:** 1. Player launches game and performs actions (enters lobby, starts match, joins party, etc.) 2. Game feeds Rich Presence update to Discord via the SDK (e.g. “In lobby”) 3. Rich Presence appears on player's Discord profile with current activity details 4. Discord friends can view the presence information 5. If including Joins/Invites, Discord Friends can "Ask to Join" or receive direct invites 6. Game feeds additional Rich Presence updates to Discord via the SDK as the player's in-game status changes (e.g. “Looking for a match”, “In a match”, etc) 7. On game shutdown, Discord automatically handles clearing player's Rich Presence **Negative Options to Resolve:** * **Network connectivity issues:** Queue presence updates and retry when connection restored * **Active and inactive clients**: Invites can complete even when one player doesn’t have the game client open on acceptance. These requirements represent the minimum standards for functionality. To create an even better player experience, see our [Design Guidelines for Rich Presence](/developers/discord-social-sdk/design-guidelines/status-rich-presence). #### Unified Friends List **Intended Use:** Combine Discord friends and in-game relationships into a single, organized friends list that shows comprehensive social connections. **Example Complete User Flow:** 1. Player opens their in-game friends list 2. Game UI quickly populates friends in an organized list showing: * In-game friends (always visible) * "Online Elsewhere" section with Discord friends not currently in-game * Appropriate status indicators and Discord badges 3. Player interacts with friends in list (message, invite, block, view profile) 4. Friends list updates dynamically in real time as statuses change 5. Player can add/remove friends through the interface **Negative Options to Resolve:** * **Friend removal:** Handle removal across both game and Discord systems appropriately * **Loading failures:** Show loading states and error messages for failed friend data retrieval * **Special characters**: Non-standard characters in Discord usernames populate as expected. * **Unlinking Discord**: Player’s in-game friends list removes Discord friend entries when they unlink their Discord account These requirements represent the minimum standards for functionality. To create an even better player experience, see our [Design Guidelines for Unified Friends List](/developers/discord-social-sdk/design-guidelines/unified-friends-list). #### Direct Messages through Discord **Intended Use:** Enable seamless messaging between players across game platforms through Discord, maintaining conversation continuity. **Complete User Flow:** 1. Player selects friend to message from an in-game friends list or other interface 2. Message interface opens showing chat history (if available) 3. Player composes and sends message 4. Message appears in both the game interface and Discord (for linked users) 5. Messages from Discord appear in-game with Discord visual notation 6. Conversation continues seamlessly across platforms **Negative Options to Resolve:** * **Message delivery failure:** Show retry options and clear error states * **Unsupported media:** Display placeholder with external link icon for rich media * **Blocked users:** Respect Discord blocking relationships and show appropriate messaging * **Network issues:** Queue messages locally and sync when connection restored These requirements represent the minimum standards for functionality. To create an even better player experience, see our [Design Guidelines for Direct Messages](/developers/discord-social-sdk/design-guidelines/direct-messages). #### Linked Channels **Intended Use:** Link in-game group chats to Discord text channels, enabling persistent conversations that flow between game platforms through Discord. **Complete User Flow:** 1. Player with Discord server admin & game chat admin permissions accesses channel linking option in group chat interface 2. Channel selection interface opens showing available Discord servers/channels 3. Player selects appropriate text channel (with proper permissions) 4. System shows setup warning if linking to restricted channel 5. Link establishes successfully with confirmation 6. Messages flow bidirectionally between game and Discord 7. Persistent entrypoint shows linked channel info and management options **Negative Options to Resolve:** * **Insufficient permissions:** Show clear error about channel management requirements * **No available channels:** Provide guidance on creating or accessing appropriate channels * **Link establishment failure:** Show retry options and clear error messaging * **User wants to unlink:** Provide confirmation dialog and clean removal process These requirements represent the minimum standards for functionality. To create an even better player experience, see our [Design Guidelines for Linked Channels](/developers/discord-social-sdk/design-guidelines/linked-channels). #### Voice Communications **Intended Use:** Provide high-quality voice chat integration that works seamlessly between game platforms through Discord. **Complete User Flow:** 1. Player joins voice-enabled game session/party 2. Voice interface becomes available with Discord-powered audio 3. Player can mute/unmute, adjust volume, see speaking indicators 4. Voice streams work for individual users with clear audio quality 5. Player can leave voice **Negative Options to Resolve:** * **Voice server unavailable:** Provide clear error messaging and retry mechanisms * **User leaves voice:** Clean up voice states and update interfaces appropriately ### Feature Access and Conveyance #### Discord Account Linking **The option for players to link their Discord account must have top-level surfacing in-game.** Social SDK integrations must not only include account linking, but also make it accessible and easily understandable for players to activate and deactivate. That means… **Access Requirements:** * Linking a Discord account is surfaced in parity with other platform-linking options. * The location for account linking is located in a **persistent and accessible** area in-game (e.g. Game Settings, Accounts menus). * The entry point for account linking is visually persistent within its associated menu location (i.e. it can’t be a one time pop up that players can’t access again). * The entry point for account linking is discoverable by players through normal expected play (i.e. not buried in a sub-menu or requiring right-click access). * The option to unlink accounts is also surfaced in-game in a persistent and easily accessible manner. * Users without linked accounts must have an associated token path for handling social features (see: [Provisional Accounts](/developers/discord-social-sdk/design-guidelines/provisional-accounts)). **Conveyance Requirements:** * Developers must provide contextual education about Discord account-linking benefits before users encounter the authorization flow. * Acceptable contextual education looks like: * **Modal or informational screen** that explains specific benefits the player will receive (e.g., "Chat with friends here and on Discord," "See what your friends are playing," "Join friends' games directly") * **Contextual tooltips or hints** near social features that explain how they improve with Discord linking * **In-game messaging** that appears when players interact with limited social features, explaining how linking would enhance the experience Discord Account Linking entry points are prohibited on Sony platforms. #### Direct Messages through Discord If you’ve chosen to integrate Direct Messages through Discord in your game, **Direct Messages must be identifiable as coming from Discord,** and **players must know when their messages are showing up in Discord.** **Conveyance Requirements:** * Cross-platform DMs need to be identified as Discord-specific through visual indicators (e.g. Discord logo/badge next to sender name, contextual information on hover about the message source) * Players must know when their messages are showing up in Discord through clear visual feedback when composing or sending messages * The messaging interface must indicate the cross-platform nature of the conversation (e.g., "This conversation syncs with Discord" or similar messaging) ### Supporting Materials To **unlock Discord text and/or voice communications for full release,** Social SDK integrations must have accompanying supporting materials in your application. You may submit your application and supporting materials under your application in the Developer Portal. **For integrations available on multiple platforms including Sony platforms, submit materials that reflect your non-Sony platform user experience.**

**For example:** Example Studio's *Wumpus Wars* is available to players on Sony PlayStation 5 and Xbox Series S and Xbox Series X. Example Studio submits the feature list and *Wumpus Wars* capture for Xbox.
#### List of SDK Features Integrated Provide a comprehensive list of all Discord Social SDK features implemented in your game, such as: * Discord Sign-in (Account Linking) * Rich Presence * Game Invites and/or Discord Joins * Unified Friends List * Direct Messages through Discord * Voice Communications * Text Communications (Linked Channels) #### Release Timeline Indicate the anticipated release date, and the current development status of your Discord integration: * Concept / Prototype * Production (Alpha) * Post-product (Beta) * Released (Already commercially available) #### Capture of Integrated Features Acceptable format: url link * **1-5 minute video capture** of the complete user flow covering each SDK feature integrated * Videos must demonstrate end-to-end user flow as outlined in [Feature Functionality](/developers/discord-social-sdk/core-concepts/communication-features#feature-functionality) * Show both successful flows and how negative options (errors, user denials) are handled * Include clear narration or on-screen text explaining each step * Ensure video quality allows reviewers to clearly see UI elements and user interactions ### Age-restricted User Protection You must comply with all age requirements under our [Social SDK Terms](https://support-dev.discord.com/hc/en-us/articles/30225844245271-Discord-Social-SDK-Terms). This includes ensuring that only people who are at least 13 years old and meet the minimum age requirements in their country can access Social SDK features integrated in your game. ### Confirmation of Standards Compliance With your application submission, **you confirm that you have met the requirements detailed above**. ## Next Steps Learn about integration steps, check platform support, and explore implementation guides: }> Learn about the integration overview and implementation steps. }> See supported platforms and download information. }> Learn how to implement messaging, voice chat, and linked channels. *** ## Change Log | Date | Changes | | ------------- | --------------- | | July 21, 2025 | initial release | [`Call`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Call.html#a1cc8a7f73c15a960bc409d734b5edbd1 [`MessageHandle`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1MessageHandle.html#ae25595b43bc74b0c4c92c5165d16382f # Core Features Source: https://docs.discord.com/developers/discord-social-sdk/core-concepts/core-features Overview of the Discord Social SDK's core features including user identity and relationships. The Discord Social SDK offers a range of features to enhance social interactions within games. Developers can leverage these features to create a more engaging and connected experience for players in their game. ## Account Linking Account linking allows a game to authenticate users with their Discord credentials, gaining access to social features like friends, chat, and presence. This process uses OAuth2 authentication. Check out our [Account Linking](/developers/platform/account-linking) platform overview for a detailed explanation of how account linking works, why it matters, and how to implement it in your game. | Development Guides | | --------------------------------------------------------------------------------------------------------------------------- | | [Account Linking from Your Game](/developers/discord-social-sdk/development-guides/account-linking-with-discord) | | [Account Linking on Mobile](/developers/discord-social-sdk/development-guides/account-linking-on-mobile) | | [Account Linking on Consoles](/developers/discord-social-sdk/development-guides/account-linking-on-consoles) | | [Account Linking from Discord Entry Points](/developers/discord-social-sdk/development-guides/account-linking-from-discord) | | Design Guidelines | | -------------------------------------------------------------------------------------- | | [Signing in with Discord](/developers/discord-social-sdk/design-guidelines/signing-in) | | [Consoles](/developers/discord-social-sdk/design-guidelines/consoles) | ## Provisional Accounts Provisional accounts let players use social features in your game without linking a Discord account so all players can have a consistent gameplay experience. | Development Guides | | ---------------------------------------------------------------------------------------------------------- | | [Using Provisional Accounts](/developers/discord-social-sdk/development-guides/using-provisional-accounts) | | Design Guidelines | | --------------------------------------------------------------------------------------------- | | [Provisional Accounts](/developers/discord-social-sdk/design-guidelines/provisional-accounts) | ## Friend System & Relationships The SDK models friendships and relationships in two ways: * Discord Friends: Persistent across all games. * Game-Specific Friends: Limited to the current game. | Development Guides | | -------------------------------------------------------------------------------------------------------------------- | | [Creating a Unified Friends List](/developers/discord-social-sdk/development-guides/creating-a-unified-friends-list) | | Design Guidelines | | --------------------------------------------------------------------------------------------- | | [Unified Friends List](/developers/discord-social-sdk/design-guidelines/unified-friends-list) | | [Game Friends](/developers/discord-social-sdk/design-guidelines/game-friends) | ## Presence & Rich Presence Presence refers to a user's online status, while Rich Presence provides game-specific activity data: * Displays if a user is online, idle, or offline. * Shows detailed game stats (e.g., what level they're playing and time played). * Allows users to send game invites through Discord and in-game. | Development Guides | | ------------------------------------------------------------------------------------------------ | | [Setting Rich Presence](/developers/discord-social-sdk/development-guides/setting-rich-presence) | | Design Guidelines | | ----------------------------------------------------------------------------------------------- | | [Status & Rich Presence](/developers/discord-social-sdk/design-guidelines/status-rich-presence) | *** ## Next Steps Learn the implementation steps, configure authentication, and explore development guides: }> Learn about messaging, voice chat, and in-game lobbies. }> Learn about the integration overview and implementation steps. }> Step-by-step guides for implementing each social feature. *** ## Change Log | Date | Changes | | ------------- | --------------- | | July 21, 2025 | initial release | # Integration Overview Source: https://docs.discord.com/developers/discord-social-sdk/core-concepts/integration-overview High-level overview of integrating the Discord Social SDK into your application. To implement the Discord Social SDK, developers for all platforms will generally follow these steps: 1. Import the SDK 2. Initialize the SDK: * Create a [`Client`] instance. * Set up event listeners to monitor SDK events and callbacks 3. Authenticate users with flexible account options * Link an existing Discord account via OAuth ([`Client::Authorize`]). * Create and manage provisional accounts for users who don't have or want a Discord account ([`Client::GetProvisionalToken`]). 4. Implement social features * Implement [unified friends list](/developers/discord-social-sdk/development-guides/creating-a-unified-friends-list) and [relationships](/developers/discord-social-sdk/development-guides/managing-relationships). * Use [rich presence](/developers/discord-social-sdk/development-guides/setting-rich-presence) for game activity updates. * Set up [lobbies](/developers/discord-social-sdk/development-guides/managing-lobbies) for multiplayer interaction and [game invites](/developers/discord-social-sdk/development-guides/managing-game-invites). * Manage [direct message](/developers/discord-social-sdk/development-guides/sending-direct-messages), [linked channels](/developers/discord-social-sdk/development-guides/creating-a-unified-friends-list), and [voice communication](/developers/discord-social-sdk/development-guides/managing-voice-chat). 5. Handle events & API calls: * Listen for changes in friend lists, presence updates, and chat messages. * Use Discord's APIs to update statuses, send messages, and manage connections. This guide is a conceptual overview. If you're ready to start building, [follow our step-by-step guide](/developers/discord-social-sdk/getting-started) to set up the SDK in your game engine. *** ## Next Steps Check platform compatibility, explore communication features, and start your integration: }> See supported platforms and download information. }> Learn about messaging, voice chat, and in-game lobbies. }> Choose your platform and follow step-by-step setup instructions. *** ## Change Log | Date | Changes | | ------------- | --------------- | | July 21, 2025 | initial release | [`Client`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a91716140c699d8ef0bdf6bfd7ee0ae13 [`Client::Authorize`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#ace94a58e27545a933d79db32b387a468 [`Client::GetProvisionalToken`]: https://discord.com/developers/docs/social-sdk/classdiscordpp_1_1Client.html#a8003130b6c46e54ac68442483bf0480c # Discord Social SDK on Mobile Source: https://docs.discord.com/developers/discord-social-sdk/core-concepts/mobile Add the Discord Social SDK to your iOS and Android games. This guide explains how to add the Discord Social SDK to your iOS and Android game. It covers what's supported on mobile, the mobile-specific setup you'll need, and where to go next for each game engine. *** ## Platform Support The Discord Social SDK is **Generally Available** on both mobile platforms: | Platform | Supported Versions | Standalone C++ | Unreal Engine | Unity | | -------- | ------------------ | -------------- | ------------- | ----- | | Android | 7.0+ | ✅ | ✅ | ✅ | | iOS | 15.1+ | ✅ | ✅ | ✅ | For the full cross-platform support matrix, see [Platform Compatibility](/developers/discord-social-sdk/core-concepts/platform-compatibility). *** ## Feature Availability on Mobile All Discord Social SDK features are available on mobile. The table below lists mobile-specific setup or behavior differences where they apply. | Feature | Mobile-Specific Notes | | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [Account Linking](/developers/discord-social-sdk/development-guides/account-linking-with-discord) | Requires deep linking (`discord-APP_ID:/authorize/callback`). Discord mobile app launches first for authentication, falls back to browser if not installed. See [Account Linking on Mobile](/developers/discord-social-sdk/development-guides/account-linking-on-mobile) | | [Provisional Accounts](/developers/discord-social-sdk/development-guides/using-provisional-accounts) | No special considerations | | [Friends & Relationships](/developers/discord-social-sdk/development-guides/managing-relationships) | No special considerations | | [Rich Presence](/developers/discord-social-sdk/development-guides/setting-rich-presence) | Requires account linking. Unlike desktop, you cannot publish presence on mobile without account linking first | | [Game Invites](/developers/discord-social-sdk/development-guides/managing-game-invites) | Requires https URL configured in Developer Portal General tab and specifying supported mobile platforms. See [Supporting Mobile Game Invites](/developers/discord-social-sdk/development-guides/managing-game-invites#supporting-mobile-game-invites) | | [Direct Messages](/developers/discord-social-sdk/development-guides/sending-direct-messages) | No special considerations | | [Lobbies & In-Game Chat](/developers/discord-social-sdk/development-guides/managing-lobbies) | No special considerations | | [Voice Chat](/developers/discord-social-sdk/development-guides/managing-voice-chat) | Request microphone permissions. See platform-specific setup: [iOS](/developers/discord-social-sdk/development-guides/account-linking-on-mobile#2-set-microphone-usage-description), [Android](/developers/discord-social-sdk/development-guides/account-linking-on-mobile#3-android-permissions) | | [Linked Channels](/developers/discord-social-sdk/development-guides/linked-channels) | No special considerations | *** ## Prerequisites Before integrating on mobile, make sure you have: * A Discord application with the Social SDK enabled. See [Getting Started](/developers/discord-social-sdk/getting-started) to create your team, application, and enable the SDK. * A mobile OAuth2 redirect URI configured in the format `discord-YOUR_APP_ID:/authorize/callback` (replace `YOUR_APP_ID` with your Discord application ID). * Your development environment set up for your target platform (Xcode for iOS, Android Studio for Android). **Reduce binary size:** You can reduce the SDK's installation size on mobile by excluding Krisp noise cancellation. See [Excluding Krisp to Reduce Installation Size](/developers/discord-social-sdk/development-guides/managing-voice-chat#excluding-krisp-to-reduce-installation-size). *** ## Choose Your Getting Started Path Select the integration that matches your project. Each guide covers download, project setup, and connecting to Discord, with mobile-specific notes where they apply. }> For custom engines or standalone applications targeting iOS and Android. }> For Unity projects building to mobile. }> For Unreal Engine projects building to mobile. *** ## Samples ### Unity Mobile Sample Check out our [Unity sample for the Discord Social SDK](https://github.com/discord/social-sdk-unity-sample), which includes a mobile scene (`Assets/Scenes/Mobile.unity`) that runs on Android and iOS. It contains easy to drop in prefabs with both code and UI to quickly integrate Discord's social features into your mobile game, with all mobile-specific configuration already set up: * Mobile redirect URI (`discord-APP_ID:/authorize/callback`) registration * Build processors that auto-inject the redirect scheme into Android manifest and iOS `Info.plist` * Portrait-optimized UI that reuses the same Discord SDK integration as the desktop scene See the **[Mobile Setup](https://github.com/discord/social-sdk-unity-sample#mobile-setup)** section in the sample's README for build instructions.