Skip to main content
Activities are web applications that run in an iframe within Discord on desktop, mobile, and web. Communication between your application and Discord uses the postMessage protocol, which the Embedded App SDK manages on your behalf. For details on available commands and their usage, see the SDK Reference. For practical examples, explore the Sample Projects.

Launching Activities

After you enable Activities in your application’s 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

Entry Point Command

Activities are primarily launched when users invoke your app’s Entry Point command from the App Launcher. When you enable Activities, a default Entry Point command called “Launch” is automatically created. By default, Discord handles opening your Activity when this command is invoked.

Interaction Response

Activities can also be launched in response to command, message component, and modal submission interactions. To open an Activity, set the callback type to LAUNCH_ACTIVITY (type 12) when responding to the interaction.

Designed for Single-Page Apps

The Embedded App SDK is intended for use with a single-page application (SPA). If you are using a framework or approach that does not fit a strict SPA model — such as a game engine — the recommended approach is to nest that framework inside your Activity’s top-level SPA and pass messages between them. See the Nested Messages App sample project for guidance.

Activity Lifecycle

1

Initialization

When your iframe is loaded within Discord, it receives 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 with the Discord client. Once the connection is established, the iframe receives a [FRAME, {evt: 'READY', ...}] message. The ready() method resolves when this handshake succeeds.
3

Authorization and Authentication

After receiving the READY payload, your application should perform authorization and authentication to acquire the necessary OAuth scopes (such as rpc.activities.write). This step is required before using scope-gated features.
4

Interacting with the Discord Client

Once authenticated, your application can subscribe to events and send commands to the Discord client. 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 re-confirmation.
5

Disconnection and Errors

Receiving a [CLOSE, {message: string, code: number}] message indicates an error or the need to restart the connection. To request a close from your side, send [CLOSE, {message?: string, code: number}]. A code other than CLOSE_NORMAL displays the message to the user; CLOSE_NORMAL results in a silent closure.

Minimal Setup Example

The example below shows the minimum setup required to connect to the Discord client. See the Sample Projects for more complete applications.
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();

  // Open the OAuth permission modal and request scopes
  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 example above: