# Developing A User-Installable App

Discord apps can be installed to servers, users, or both. This guide will walk you through building a basic game integration app that is installable to both Discord users and servers.

While the tutorial will focus on supporting different [installation contexts](/docs/resources/application#installation-context), we'll be building a basic game integration along the way with a wiki lookup with user-specific bookmarking and a server leaderboard. The app has four commands (`/link`, `/profile`, `/leaderboard`, and `/wiki`) that can be run in different installation and interaction contexts (which are concepts we'll dig into later in the tutorial).

<Collapsible title="Resources used in this guide" description="Overview of the tools and technologies we'll use" icon="list">

- **[GitHub repository](https://github.com/discord/user-install-example)** where the code from this guide lives.
- **[discord-interactions](https://github.com/discord/discord-interactions-js)**, a library that provides types and helper functions for Discord apps.
- **[Express](https://expressjs.com/)**, a popular JavaScript web framework we'll use to create a server where Discord can send requests.
- **[ngrok](https://ngrok.com/)**, a tool that lets us tunnel our local server to a public URL where Discord can send requests.
</Collapsible>

---

## Step 0: Project Setup

Before we dig in, you'll need the project code from the [sample app repository](https://github.com/discord/user-install-example).

<Collapsible title="Project structure" description="Overview of the project structure for the sample app used in this tutorial" icon="code">
```
├── .env.sample -> sample .env file
├── app.js      -> main entrypoint for the app
├── commands.js -> slash command payloads + helpers
├── game.js     -> logic specific to the fake game
├── utils.js    -> utility functions and enums
├── package.json
├── README.md
└── .gitignore
```
</Collapsible>

:::info
We'll be developing our app locally with a little help from [ngrok](https://ngrok.com/), but you can use your preferred development environment.
:::

If you don't have [NodeJS](https://nodejs.org/en/download/) installed, install that first.

Now, clone the project code to your machine using the command line:

```
git clone https://github.com/discord/user-install-example.git
```

Then navigate to the directory and install the project's dependencies:

```
# navigate to directory
cd user-install-example

# install dependencies
npm install
```

With that out of the way, open your new project in the code editor of your choice, then we'll move ahead to setting up your Discord app.

## Step 1: Creating an App

First, you'll need to create an app in the developer portal if you don't have one already:

<LinkButton to="https://discord.com/developers/applications?new_application=true" color="brand" text="Create App" />

Enter a name for your app, then press **Create**.

After you create your app, you'll land on the **General Overview** page of the app's settings where you can update basic information about your app like its description and icon.

### Fetching app credentials

While we're in your app's settings, we'll want to get a few sensitive values for your app, like its token and ID.

:::warn
Your token is used to authorize API requests and carry your app's permissions, so they are *highly* sensitive. Make sure to never share your token or check it into any kind of version control.
:::

Back in your project folder, rename the `.env.sample` file to `.env`. `.env` is where we'll store all of your app's credentials.

We'll need three values from your app's settings for your `.env` file:

- On the **General Information** page, copy the value for **Application ID**. In `.env`, replace `<YOUR_APP_ID>` with the ID you copied.
- Back on the **General Information** page, copy the value for **Public Key**, which is used to ensure HTTP requests are coming from Discord. In `.env`, replace `<YOUR_PUBLIC_KEY>` with the value you copied.
- On the **Bot** page under **Token**, click "Reset Token" to generate a new bot token. In `.env`, replace `<YOUR_BOT_TOKEN>` with your new token.

Now that you have the credentials you need, we'll configure your app to support different installation contexts.

### Add Guild Members intent

The sample app fetches members in the server when constructing a fake game leaderboard. Getting server members requires a special permission called a [privileged intent](/docs/events/gateway#privileged-intents), so we'll add that to our app.

Go to the **Bot** page and find the **Privileged Gateway Intents** section. Toggle "Server Member Intent" to be active.

### Choosing Supported Installation Contexts

An app's **[installation context](/docs/resources/application#installation-context)** defines how it's installed: to a server, to a user, or both.

We're going to configure our app to support both installation contexts, and while that's a good default for most apps, some apps may only make sense in one context or the other.

In your app's settings, go to the **Installation** page from the sidebar. Under **Installation Contexts**, check both **User Install** and **Guild Install**, then press **Save Changes**.

### Configuring Default Install Settings

The default install settings of your app determines the default [scopes](/docs/topics/oauth2#shared-resources-oauth2-scopes) and [bot user permissions](/docs/topics/permissions) for each supported installation context. At the moment, apps installed to a user context only support the `applications.commands` scope (which allows your app to install [commands](/docs/interactions/application-commands)) in the default install settings.

###### Update Install Link

Before adding default install settings, we need to select Discord Provided Link for the app's [install link](/docs/resources/application#install-links). Under the **Install Link** section, select `Discord Provided Link` from the dropdown if it isn't already selected (it should be by default). Once it's selected, the **Default Install Settings** will appear.

###### Adding Default Install Settings

Under the **Default Install Settings** section:
- For **User Install**, add the `applications.commands` scope
- For **Guild Install**, add the `applications.commands` scope and `bot` scope. When you select `bot`, a new **Permissions** menu will appear to select the bot user's permissions. Select any permissions that you may want for your app—for now, I'll just select `Send Messages`.

:::info
Permissions for a bot user are very similar to permissions for other Discord users. Details about permissions, and a list of available permissions is on the [Permissions](/docs/topics/permissions#permissions-bitwise-permission-flags) page.
:::

After you've selected the scopes and permissions for your app, click **Save Changes**.

![Installation settings in App Settings](images/user-install-settings.webp)

### Installing your app

Finally, we'll install your new app to both a test server and your user account so that we can test in both installation contexts.

###### Install to server

To install your app to your test server, copy the default Install Link for your app from the **Installation** page. Paste the link in your browser and hit enter, then select "Add to server" in the installation prompt.

Select your test server, and follow the installation prompt. Once your app is added to your test server, you should see it appear in the member list.

###### Install to user account

Next, install your app to your user account. Paste the same Install Link in your browser and hit enter. This time, select "Add to my apps" in the installation prompt.

Follow the installation prompt to install your app to your user account. Once it's installed you can open a DM with it.

## Step 2: Setting Up Commands

Next, we'll register the [application commands](/docs/interactions/application-commands) for our app. But before touching code, it's important to understand the concept of command contexts:

<Collapsible title="Contexts for application commands" description="A brief introduction to command contexts" icon="view" open="true">

Commands have two context fields that can be set when creating or updating a command which let you limit the supported install methods and surfaces in Discord for that command:

- **`integration_types`** lets you control which **[installation contexts](/docs/interactions/application-commands#installation-context)** a command is supported (user, guild, or both). For example, the `/link` and `/profile` commands we'll be creating are only available when the app is installed to a user.
- **`contexts`** lets you set the **[interaction contexts](/docs/interactions/application-commands#interaction-contexts)**, or the surfaces in Discord, where a command can be used (in a guild channel, in your bot user's DM, and within other DMs or GDMs). For example, the `/leaderboard` command we'll be creating is only available when the command is run from a guild channel.

More information and details about command contexts are in the [contexts](/docs/interactions/application-commands#contexts) documentation, but for now we'll get a better understanding of contexts by using them in our sample app.
</Collapsible>

### Commands in the sample project

We'll be setting up four commands for our sample app that all have *slightly* different contexts, which are included in the table below:

| Name           | Description                                            | Installation Contexts (`integration_types`) | Interaction Contexts (`contexts`)    |
|----------------|--------------------------------------------------------|---------------------------------------------|--------------------------------------|
| `/leaderboard` | View game leaderboard for the current server           | `GUILD_INSTALL`                             | `GUILD`                              |
| `/wiki`        | Find information about game items and characters       | `GUILD_INSTALL`, `USER_INSTALL`             | `GUILD`, `BOT_DM`, `PRIVATE_CHANNEL` |
| `/profile`     | Get information about your game inventory and progress | `USER_INSTALL`                              | `GUILD`, `BOT_DM`, `PRIVATE_CHANNEL` |
| `/link`        | Link your game account to Discord                      | `USER_INSTALL`                              | `BOT_DM`                             |

:::info
The supported installation contexts for a command affects which interaction contexts you can set. Specifically, the `PRIVATE_CHANNEL` interaction context can only be included in `contexts` if `USER_INSTALL` is included in `integration_types` for the command. Read details in the [documentation](/docs/interactions/application-commands#contexts).
:::

The payloads for our app's commands are in `commands.js` in the project folder in case you want to change any values or see what the command's context fields (`integration_types` and `contexts`) look like for each of the commands in the table above.

### Registering the commands

Now let's register your app's commands so you can see them in Discord. In your project folder run:

```
npm run register
```

The register command will call the [Create Global Application Command](/docs/interactions/application-commands#create-global-application-command) endpoint for each of the command payloads in `commands.js`.

After your new commands have been created, you can go into Discord and look for the commands in the surfaces where we made them available:
- In **channels within the guild you installed your app**, you should see `/leaderboard`, `/wiki`, and `/profile`
- In **channels within any of your guilds**, you should see `/wiki` and `/profile`
- In **your app's DM**, you should see `/wiki`, `/profile`, and `link`
- And finally, **in DMs or GDMs with other users**, you should see `/wiki` and `/profile`

However, if you try to run any of the commands, you'll get an error :(

...let's fix that.

## Step 3: Handling Interactivity

To receive and handle interactive requests, we'll set up an **Interactions Endpoint URL**, which is a public URL where Discord sends your app's interactions.

### Set up a public endpoint

To set up a public endpoint we'll start our app, which runs an [Express](https://expressjs.com/) server, then use [ngrok](https://ngrok.com/) to expose our server publicly. 

First, go to your project's folder and run the following to start your app:

```
npm run start
```

There should be some output indicating your app is running on port 3000. Behind the scenes, our app is ready to handle interactions from Discord, which includes verifying security request headers and responding to `PING` requests. We're skipping over a lot of the details in this tutorial, but details about preparing apps for interactions is in the [Interactions Overview](/docs/interactions/overview#preparing-for-interactions) documentation.

:::info
By default, the server will listen to requests sent to port 3000, but if you want to change the port, you can specify a `PORT` variable in your `.env` file.
:::

Next, we'll start our ngrok tunnel. If you don't have ngrok installed locally, you can install it by following the instructions on the [ngrok download page](https://ngrok.com/download).

After ngrok is installed locally, open a new terminal and create a public endpoint that will forward requests to your Express server:


```
ngrok http 3000
```

The output will include a **Forwarding** URL, which is the publicly-accessible URL we'll use for our Interactions Endpoint URL in the next step.

### Configuring an interaction endpoint URL

Let's configure our app's **Interaction Endpoint URL**.

Go to your [app's settings](https://discord.com/developers/applications) and on the **General Information** page under **Interaction Endpoint URL**, paste your new ngrok URL and append `/interactions` (it'll be something like `https://84c5df474.ngrok-free.dev/interactions`).

Click **Save Changes** and if all is well, your Interactions Endpoint URL should be verified by Discord.

:::info
If you have troubles verifying your endpoint, make sure both ngrok and your app is running on the same port, and that you've copied the ngrok URL correctly
:::

### Understanding metadata for interactions

Now that our Interactions Endpoint URL is set up, we should now be able to run our app's commands. Go to your app's DM and run `/profile`, and your app should respond with a sample game profile.

Back on the command line, our app is logging incoming requests from Discord, so you can see what the request body for your command invocation looked like.

<Collapsible title="Sample interaction payload" icon="code" open="true">
The payload below is condensed to be more readable, but your interaction request body should look something like this:

```json
{
  "app_permissions": "442368",
  "application_id": "234248956100616262",
  "authorizing_integration_owners": { "1": "1090372582781497424" },
  "channel": {
    // Partial channel object corresponding to channel_id
  },
  "channel_id": "1234563982236504123",
  "context": 1,
  "data": { "id": "1234358421659193405", "name": "link", "type": 1 },
  "entitlements": [],
  "id": "1234968734674853908",
  "locale": "en-US",
  "token": "a really long interactions token that your app can use to respond to the interactions",
  "type": 2,
  "user": {
    // Partial user object
  },
  "version": 1
}
```

</Collapsible>

To see which command was run, you can look at the [`data` object](/docs/interactions/receiving-and-responding#interaction-object-interaction-data).

However, for this tutorial, we're going to focus more on the metadata related to installation and interaction contexts. There are a few metadata fields you'll want to pay attention to when building an app that can be installed to multiple interaction contexts—

###### `context`

`context` tells you which [interaction context](/docs/interactions/application-commands#interaction-contexts) the command was invoked from. Since I triggered the command from my app's DM the `context` is `1` (or `BOT_DM`).

With interaction context, something to keep in mind in `BOT_DM` is only the *DM with your bot user*. If you run the same command in a DM with your bestie, or in a group DM, the interaction context will be `PRIVATE_CHANNEL` (`2`).

###### `authorizing_integration_owners`

`authorizing_integration_owners` provides data about any ID relevant to the installation context(s) associated with the interaction. 

The keys in the object are the relevant installation context(s) (`GUILD_INSTALL`/`"0"` and/or `USER_INSTALL`/`"1"`). The values depend on the key, but for `USER_INSTALL` the key will always be the ID of the user that authorized your app.

:::info
`authorizing_integration_owners` is not the same as the user that triggered the interaction. Information about the user that triggered the interaction is in the `user` object.
:::

Understanding the authorization owner can be helpful when handling interactions from message components for apps installed to a user, which is discussed more in the [message component interactions](/docs/tutorials/developing-a-user-installable-app#using-metadata-for-message-component-interactions) section. Or you can find technical details in the [Authorizing Integration Owners](/docs/interactions/receiving-and-responding#interaction-object-authorizing-integration-owners-object) documentation.

###### `app_permissions`

`app_permissions` are the bitwise set of permissions your app has in the place where the interaction was triggered. The permissions your app has will be different for DMs with your app, in servers, and G(DM)s with other users.

In the sample payload, the value is `"442368"`.

These values can be helpful when deciding how you want your app to [respond to the interaction](/docs/interactions/receiving-and-responding#responding-to-an-interaction). For example, perhaps you want your app to respond ephemerally when a specific command is invoked from a server, which the sample app does for the `/profile` command.

### Using metadata for command interactions

As mentioned above, the `/profile` command for our app will respond ephemerally, meaning only the invoking user will see the response, when invoked from a server. If it's invoked within a DM with the bot user, it'll respond with a non-ephemeral message. In the project, you can see this logic in `app.js` when handling the `/profile` command:

<Collapsible title="Using context for the profile command" icon="code" >

Below is the logic for handling the `/profile` command. When the context for the interaction is in a server, we'll make our interaction response ephemeral and add a button so the user can share their profile if they want.

```javascript
// "profile" command
if (name === 'profile') {
  const profile = getFakeProfile(0);
  const profileEmbed = createPlayerEmbed(profile);

  // Use interaction context that the interaction was triggered from
  const interactionContext = req.body.context;

  // Construct `data` for our interaction response. The profile embed will be included regardless of interaction context
  let profilePayloadData = {
    embeds: [profileEmbed],
  };

  // If profile isn't run in a DM with the app, we'll make the response ephemeral and add a share button
  if (interactionContext !== 1) {
    // Make message ephemeral
    profilePayloadData['flags'] = 64;
    // Add button to components
    profilePayloadData['components'] = [
      {
        type: 1,
        components: [
          {
            type: 2,
            label: 'Share Profile',
            custom_id: 'share_profile',
            style: 2,
          },
        ],
      },
    ];
  }

  // Send response
  return res.send({
    type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
    data: profilePayloadData,
  });
}
```
</Collapsible>

In the sample app code, we assign the value of `context` in the request body to a new `interactionContext` variable. Based on the context, we modify how we respond to the command interaction. If it was run in a guild or within a G(DM) other than the DM with the app's bot user, `flags` is set to `64` to make the response ephemeral, and a new button component is added so that the user can share their profile if they want.

### Using metadata for message component interactions

Message component interactions can be triggered by any user the component is visible to, regardless of the installation context. Since potentially any user can trigger the component, it can be helpful to use metadata to understand context about the installation.

Consider we added a new `/game` command supported in the `USER_INSTALL` installation context that a user could trigger to send a message to whatever guild or group DM they're in to ask others if they're interested in joining a game match:

![Sample game command response](images/user-install-game-message.webp)

When someone clicks on the button, our app would care about two users when handling the interaction:
1. User B, who clicked the "Join" button so our app can track who is interested in joining the match
2. User A, who ran the `/game` command so our app can tell them who is interested in joining the match

There are two additional fields to know about that can be helpful in this scenario—

###### `interaction_metadata`

Messages created in response to an interaction will include an [`interaction_metadata` object](/docs/resources/message#message-interaction-metadata-object) which includes metadata related to the interaction.

###### `authorizing_integration_owners`

`authorizing_integration_owners` was touched on above, but it's worth highlighting again since it's most helpful when handling message component interactions for user-installed apps.

For user-installed apps, it can be used to differentiate between the user that installed an app and the user that triggered an app's interaction since messages sent in response to interactions (either an interaction response or a follow-up message) can be visible to users that don't have the app installed to their account.

## Next Steps

*Yay~!* At this point, you have an app that supports both installation contexts and understand the basics of using metadata to support different contexts. Now you can go explore the documentation for details, or play with the sample app to develop more complex features.

<Container>
  <Card title="Interactions documentation" link="/docs/interactions/overview">
    Explore the Interactions documentation to learn more about receiving and responding to commands and message components
  </Card>
  <Card title="Github repository" link="https://github.com/discord/user-install-example">
    GitHub repository with sample project
  </Card>
</Container>