diff --git a/docs/Change_Log.md b/docs/Change_Log.md
index fc41abb3e0..7781463e82 100644
--- a/docs/Change_Log.md
+++ b/docs/Change_Log.md
@@ -1,5 +1,19 @@
# Change Log
+## Discord Activities: Developer Preview of the Embedded App SDK
+
+#### March 18, 2024
+
+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](#DOCS_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](#DOCS_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](#DOCS_ACTIVITIES_OVERVIEW).
+
## Enforced Nonces on Create Message Endpoint
#### February 12, 2024
diff --git a/docs/Intro.mdx b/docs/Intro.mdx
index 812147408d..a856f6b8a0 100644
--- a/docs/Intro.mdx
+++ b/docs/Intro.mdx
@@ -24,6 +24,10 @@ Plus, use the [Gateway API](#DOCS_TOPICS_GATEWAY) to respond to [real-time event
Link and update metadata to enhance Discord for users. Add [Rich Presence](#DOCS_GAME_SDK_ACTIVITIES) to display live data on users' profiles, or [connection metadata](#DOCS_RESOURCES_APPLICATION_ROLE_CONNECTION_METADATA) to make it easy for admins to create roles using metadata associated with your app.
+#### Build Interactive Activities and Games
+
+Currently in Developer Preview, the [Embedded App SDK](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK) allows you to build [Activities](#DOCS_ACTIVITIES_OVERVIEW), such as multiplayer games or social experiences, that run inside Discord.
+
## Discover Developer Resources
#### Find Tools and Libraries
diff --git a/docs/activities/Building_An_Activity.mdx b/docs/activities/Building_An_Activity.mdx
new file mode 100644
index 0000000000..c6457b2dd2
--- /dev/null
+++ b/docs/activities/Building_An_Activity.mdx
@@ -0,0 +1,617 @@
+# Building Your First Activity in Discord
+
+> preview
+> Creating Activities is currently available as a [Public Developer Preview](#DOCS_ACTIVITIES_OVERVIEW/public-developer-preview).
+
+## Introduction
+
+Discord Activities are web applications that can run inside Discord. This allows you to build rich, multiplayer experiences inside of Discord.
+
+If this is your first time learning about Activities, check out the [Activities Overview](#DOCS_ACTIVITIES_OVERVIEW) for more information and a collection of sample apps.
+
+### Let's Jump In!
+
+For your first Activity, we'll be building an app in JavaScript with the following goals:
+- [Create a new Discord App](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY/step-1-creating-a-new-app)
+- [Launch your app from within a voice channel](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY/step-4-running-your-app-locally-in-discord)
+- [Authorize and authenticate with the user](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY/step-5-authorizing-authenticating-users)
+- [Fetch and display the name of the current voice channel](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY/step-6-use-the-sdk-to-fetch-the-channel)
+- [Fetch and display the avatar of the current server](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY/step-7-use-the-api-to-fetch-the-guild)
+
+![Building Your First Activity Tutorial](activities/tutorial-hero.png)
+
+> info
+> This example is intended to illustrate how a basic web application works while embedded inside of Discord. For more advanced examples, please see our [Sample Projects](#DOCS_ACTIVITIES_OVERVIEW/sample-projects).
+
+---
+
+## Prerequisites
+
+The [Embedded App SDK](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK) is intended to abstract away some of the complexities in building a Discord Activity, but developing a full-featured, multiplayer experience requires extensive experience with JavaScript and other web technologies.
+
+If you are still learning to program, there are many free education resources to take advantage of:
+- [The Odin Project](https://www.theodinproject.com/paths/foundations/courses/foundations)
+- [Codecademy](https://www.codecademy.com/learn/paths/web-development)
+- [Khan Academy](https://www.khanacademy.org/computing/computer-programming/programming)
+- [Discord Developers Server](https://discord.gg/pAA2RScK)
+
+Concepts that are important to know before continuing:
+
+- [Asynchronous JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function): You will be working with async JavaScript method calls to communicate with the Discord client and API
+- [React](https://react.dev/), [Vue](https://vuejs.org/), or another frontend framework for building user interfaces
+
+
+- **[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 for building Discord 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 authenticatication 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
+
+
+---
+
+> preview
+> During the Developer Preview, it is recommended you create a new app for testing purposes. There are [limitations for Activities](#DOCS_ACTIVITIES_OVERVIEW/public-developer-preview) during this preview period.
+
+## Step 1: Creating a new app
+
+First, create a new app in the developer portal.
+
+Enter a name for your app, select a team, then press **Create**.
+
+![Create a new app](activities/new-app.png)
+
+> info
+> **Development Team Access** While developing your application, it will only be launchable or joinable by your user or any member of your developer team. It often makes sense to make a [developer team](https://discord.com/developers/teams) and set the team as the application's owner, especially if you know you will collaborate with others during the development phase.
+
+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.
+
+### Configure Your Activity
+
+Navigate to `Activities -> Getting Started` in the sidebar.
+
+Review this page and press 'Get Started' to make your app eligible for being embedded.
+
+![Configure your Activity](activities/getting-started-activities.png)
+
+From the `Activities` section of the developer portal, you can configure:
+
+- URL Mappings
+- Settings
+- Art Assets
+
+We'll come back to this page later in this guide when we are ready to set up our URL Mappings.
+
+### Find Your OAuth2 Credentials
+
+To use Discord-related information, such as a user's username, avatar, or guild avatar, a user must agree to grant OAuth scopes to your application. Learn more about scopes [in the OAuth2 documentation](#DOCS_TOPICS_OAUTH2/shared-resources-oauth2-scopes).
+
+There are two OAuth2 identifiers your app will need to reference: [CLIENT ID](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY/client-id) and [CLIENT SECRET](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY/client-secret), which are located on the `Settings -> OAuth2` tab on the developer portal.
+
+Find these values and hold on to them for a later step.
+
+
+
+![oauth2-details](activities/oauth2-details.png)
+
+### Client ID
+
+Also known as the Application ID. This is the public facing id linked to your application.
+
+### Client Secret
+
+This is a private identifier that your app will use to grant an OAuth2 `access_token`. It should never be stored in the client-side JavaScript code.
+
+
+### You must set up a OAuth2 redirect URI in order for this example to work.
+
+The URI should point to the location where you host your app. If you don't yet have a url, you should fill in the field with a placeholder, such as https://127.0.0.1.
+
+![Configure your Activity](activities/oauth2-redirect.png)
+
+---
+
+## Step 2: Setting up project files
+
+We will use git to pull down a scaffolded project to help you get started quickly.
+
+This tutorial's template includes a minimal frontend and backend with vanilla JavaScript, Node.js, Express, and [Vite](https://vitejs.dev/).
+
+When you build your applications, you can use whatever backend language and framework you prefer, but we will focus on JavaScript for this guide.
+
+```
+git clone git@github.com:discord/getting-started-activity.git
+cd getting-started-activity
+```
+
+This git clone will pull down a template in a `getting-started-activity` directory for you to get started with.
+
+
+```
+├── 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
+```
+
+### Set Up Your Environment Variables
+
+In the root of your project folder is an example.env file. Let's copy that example file into a new `.env` file.
+
+```
+cp example.env .env
+```
+
+`getting-started-activity/.env`
+```
+VITE_DISCORD_CLIENT_ID=YOUR_OAUTH2_CLIENT_ID_HERE
+DISCORD_CLIENT_SECRET=YOUR_OAUTH2_CLIENT_SECRET_HERE
+```
+
+> info
+> **Why is there a VITE_ prefix before our Client ID?** Prefixing the `DISCORD_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. [Read more in the Vite docs](https://vitejs.dev/guide/env-and-mode)
+
+Any `VITE_` prefixed variables are then made available to us in our code via `import.meta.env` such as `import.meta.env.VITE_DISCORD_CLIENT_ID`.
+
+> warn
+> **Secure Your Secrets** Your `DISCORD_CLIENT_SECRET` and `DISCORD_BOT_TOKEN` should always be considered sensitive secrets. When using other programming languages and frameworks, it is safe to have your CLIENT_ID public and available to the browser.
+
+### Set Up Your Frontend
+
+Now that our environment variables are set up, let's spin up our frontend.
+
+
+```
+# from inside the getting-started-activity/ directory:
+
+cd client
+npm install
+npm run dev
+```
+
+If you visit http://localhost:5173/ you will see a vanilla JS frontend template running with [Vite](https://vitejs.dev/). If you look at the code from the template, you can see that it renders an image but is not calling any Discord APIs or backend services. We will come back to this later in the guide.
+
+---
+
+## Step 3: Installing the Embedded App SDK
+
+With our frontend running, it's time to start integration with the Discord client!
+
+
+
+From inside our `getting-started-activity/client` folder, we will install the 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.
+
+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 earlier. The `VITE_DISCORD_CLIENT_ID` variable is available to us through `import.meta.env`.
+
+We also set up our check for the `ready` event with an async/await function. This allows us to output a log or take action once the initial handshake was successful.
+
+Let's import and instantiate the SDK in `getting-started-activity/client/main.js`:
+```js
+// 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!
+
+`;
+```
+
+
+> warn
+> **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 you app in Discord.
+
+---
+
+## Step 4: Running your app locally in Discord
+
+Let's ensure everything is wired up correctly before we move on to authenticating with Discord.
+
+To run your application locally, we recommend a network tunnel, such as `cloudflared` or `ngrok.`
+
+In one terminal, let's start our client-side app:
+
+```
+cd client
+npm run dev
+```
+
+`client terminal output`
+```
+VITE v5.0.12 ready in 100 ms
+
+➜ Local: http://localhost:5173/
+➜ Network: use --host to expose
+➜ press h + enter to show help
+```
+
+Let's start our network tunnel for port 5173 in another terminal window.
+
+```
+cloudflared tunnel --url http://localhost:5173
+```
+
+When you run `cloudflared`, the tunnel will generate a public URL for you that we will use in the next step.
+
+```
+Your quick Tunnel has been created! Visit it at (it may take some time to be reachable):
+https://funky-jogging-bunny.trycloudflare.com
+```
+
+Let's copy that URL and take it into our next step.
+
+### Set up your Activity URL Mapping
+
+To serve your application, you must set up a URL mapping to where your app is hosted. For this tutorial, your app is hosted locally and being served via your network tunnel.
+
+Click on `Activities` -> `URL Mappings` in your application settings. Enter the URL you generated from `cloudflared` in the previous step.
+
+![Configuring your URL Mapping](activities/url-mapping-tutorial.png)
+
+| PREFIX | TARGET |
+|--------|-----------------------------------------|
+| `/` | `funky-jogging-bunny.trycloudflare.com` |
+
+Read more about the specific rules and details for URL mapping [here](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/url-mapping).
+
+### Enable Developer Mode in your Client
+
+One more step before we can see our work inside of Discord!
+
+If you haven't already, go to your `User Settings` -> `Advanced` and toggle on the `Developer Mode` setting. Developer Mode exposes context menu items for building apps, including giving you access to Activities that you are working on.
+
+![Enabling Developer Mode in Settings](activities/developer-mode.gif)
+
+### Running your Activity in Discord
+
+Now that we are pointing Discord to our locally running app, we can launch it in Discord!
+
+In a voice channel in your Discord server, click on the Activities icon (🚀) to see your Activity at the top of the Activity Shelf.
+
+Clicking on your app will launch your locally running app from inside Discord!
+
+![Running your activity](activities/start-activity.png)
+
+> info
+> **Customizing your Activity** If you'd like to set images for your Activity, you can learn how to do that [here](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/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.
+
+---
+
+## Step 5: Authorizing & authenticating users
+
+To fully 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](activities/oauth-flow-diagram.svg)
+
+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/blob/main/examples/discord-embedded-app-starter/packages/server/src/app.ts)
+- [Front-end code](https://github.com/discord/embedded-app-sdk/blob/main/examples/discord-embedded-app-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.
+
+
+```javascript
+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}`);
+});
+```
+
+
+```
+npm run dev
+```
+
+`server terminal output`
+```
+> 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 our [Sample Projects](#DOCS_ACTIVITIES_OVERVIEW/sample-projects).
+
+### 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.
+
+> info
+> **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/).
+
+`getting-started-activity/client/main.js`
+
+```javascript
+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",
+ ],
+ });
+
+ // 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` and `guilds` scopes.
+
+![Prompt to authorize Activity](activities/tutorial-auth.png)
+
+> warn
+> **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.
+
+> info
+> If you want to remove the authorization, you can view your application under `Authorized Apps` under your user profile. If you click the `Deauthorize` button next to your app, you can go through the OAuth2 flow when you relaunch 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 voice channel that our activity is running in. We can do this by writing a new async function that uses the `commands.getChannel` SDK method.
+
+`getting-started-activity/client/main.js`
+
+```javascript
+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.innerHTML = textTagString;
+ app.appendChild(textTag);
+}
+```
+
+Now, let's update the callback after `setupDiscordSdk()` to call our new function. If we close and rejoin our activity in Discord, we should now see the name of the current channel in our app!
+
+```javascript
+setupDiscordSdk().then(() => {
+ console.log("Discord SDK is authenticated");
+
+ appendVoiceChannelName();
+});
+```
+
+Now when we launch our Activity, we will dynamically see the name of our voice channel populate in our app.
+
+![Discord Activities](activities/tutorial-channel-name.png)
+
+---
+
+## 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 use the `/users/@me/guilds` endpoint in combination with `auth.access_token` to get a list of the guilds we are in.
+- We will then iterate over each guild to find the guild we are in based on the `guildId` defined in discordSdk.
+- Finally, we can create a new HTML image element with the guild avatar and append it to our application.
+
+> info
+> In this example, we use a pure `fetch` request to call the REST API. However, this is a great place to use your favorite Discord JavaScript library alongside the Embedded App SDK.
+
+`getting-started-activity/client/main.js`
+
+```javascript
+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://discord.com/developers/docs/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);
+ }
+}
+```
+
+Finally, let's call our new function that uses the Discord API.
+
+```javascript
+setupDiscordSdk().then(() => {
+ console.log("Discord SDK is authenticated");
+
+ appendVoiceChannelName();
+ appendGuildAvatar();
+});
+```
+
+If we relaunch our Activity, we will also see our the current server's avatar render in our app.
+
+![Discord Activities](activities/tutorial-hero.png)
+
+---
+
+## 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.
+
+You can now explore our more extensive [development guides](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES) and [design patterns](#DOCS_ACTIVITIES_DESIGN_PATTERNS) to consider when building your app.
+
+### Sample projects to try out next
+- Start with a blank slate using our [Discord Activity Starter](https://github.com/discord/embedded-app-sdk/tree/main/examples/discord-activity-starter) project
+- Try out the full range of SDK features in our [Embedded App SDK Playground](https://github.com/discord/embedded-app-sdk/tree/main/examples/sdk-playground)
+- Support multiplayer & state management using our [React Colyseus](https://github.com/discord/embedded-app-sdk/tree/main/examples/react-colyseus) project
+- Learn more about working with game engines and the [Nested Messages](https://github.com/discord/embedded-app-sdk/tree/main/examples/nested-messages) project
+
+### Support & Feedback
+During this Developer Preview, you can get support and report issues:
+
+- Come find us in the `#activities-dev-help` channel in the [Discord Developers Server](https://discord.gg/discord-developers)
+- Report issues in the [Embedded App SDK Github repo](https://github.com/discord/embedded-app-sdk)
+- Reach out to our [Developer Support](https://dis.gd/developer-activities) team if you have any questions about the SDK
+- Join us in the **[Discord Developers server](https://discord.gg/discord-developers)** to attend events hosted by the Discord team and chat with other Discord community developers
diff --git a/docs/activities/Design_Patterns.mdx b/docs/activities/Design_Patterns.mdx
new file mode 100644
index 0000000000..29ca547403
--- /dev/null
+++ b/docs/activities/Design_Patterns.mdx
@@ -0,0 +1,220 @@
+# Activity Design Patterns
+
+> preview
+> These design patterns were developed while working with partners ahead of the Developer Preview. We will continue to update these as we release new features for 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](activities/bobble-bash.png)
+
+
+### 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](activities/bobble-league.png)
+
+### 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](#DOCS_ACTIVITIES_DESIGN_PATTERNS/quality-and-testing) for key areas of minimum quality support and testing recommendations.
+- See the below [Technical Considerations](#DOCS_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](activities/eights.png)
+
+### 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 useable 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/chess-victory.png)
+
+#### Activities in Text Channels
+> preview
+> Activities support in text channels is expected later in 2024.
+- The Activity user interace, 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
+
+> preview
+> 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.
+- Note: This behavior will change in 2024, when we release persistent instances.
+
+### 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 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.
\ No newline at end of file
diff --git a/docs/activities/Development_Guides.mdx b/docs/activities/Development_Guides.mdx
new file mode 100644
index 0000000000..f27930154d
--- /dev/null
+++ b/docs/activities/Development_Guides.mdx
@@ -0,0 +1,923 @@
+# Activity Development Guides
+
+> preview
+> Creating Activities is currently available as a [Public Developer Preview](#DOCS_ACTIVITIES_OVERVIEW/public-developer-preview).
+
+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.
+
+
+ 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.
+
+
+
+## Assets & Metadata
+
+
+ Best practices for configuring how your application shows up in Discord.
+
+
+ Best practices for configuring how your application shows up in Discord.
+
+
+
+## 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.
+
+
+
+---
+### 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"](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/url-mapping) URL.
+
+To run your locally hosted application, follow the instructions for [Launching your Application from the Discord Client](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/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 the Developer Preview for Activities.
+3. Set up the application's [URL mapping](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/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.
+
+> info
+> 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](activities/url-mapping-tutorial.png)
+
+> warn
+> 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](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/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 the Developer Preview for Activities.
+3. Set up the application's [URL Mapping](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/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](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/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](activities/application-test-mode-prod.gif)
+
+
+---
+
+### 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` 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`
+3. Close the settings window and enter a voice channel.
+4. 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".
+6. 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
+5. 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
+
+> preview
+> This is only possible once the Developer Preview Activities is enabled on your application.
+
+To add or modify your application's URL mappings, click on `Activities -> URL Mappings` and set the prefix and target values for each mapping as needed.
+
+![Configuring your URL Mapping](activities/url-mapping-tutorial.png)
+
+#### 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` |
+- 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](activities/url-mapping-do.png) | ![url-mapping-dont.png](activities/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`
+- `https://canary.discord.com`
+- `https://ptb.discord.com`
+- `https://cdn.discordapp.com`
+- `https://media.discordapp.net`
+
+---
+
+### 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](activities/debug-logs-filtering.gif)
+
+#### 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
+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
+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!',
+});
+```
+
+---
+
+### 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
+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](activities/external-link-modal.png)
+
+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](https://discord.com/developers/docs/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 Channels. Similarly, this command returns an error if the user has invalid permissions for the channel, so using `getChannelPermissions` (requires OAuth scope `'guild.members.read'`) is highly recommended.
+
+#### Usage
+
+```javascript
+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](activities/invite-dialog.png)
+
+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
+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
+
+![share-moment-dialog](activities/share-moment-dialog-example.png)
+
+
+---
+
+### 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
+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](activities/encourage-hardware-acceleration-modal.png)
+
+
+---
+
+### 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
+- Select your application
+- Select `Activities` -> `Settings` in the left-side of the developer portal, or visit `https://discord.com/developers//embedded/settings`
+- From check the appropriate checkboxes in the developer portal, and save your changes
+
+![supported-platforms](activities/supported-platforms.png)
+
+---
+
+### Mobile Safe Areas
+
+As an example, you can define your safe area insets as below in CSS:
+
+```
+: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:
+
+```
+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
+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
+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.
+
+> info
+> On Android devices, the thermal state updates will only be available on Android 10 and higher.
+
+---
+
+### 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
+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](activities/default_orientation_lock_state.png)
+
+#### 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
+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
+export default function LayoutMode() {
+ const handleLayoutModeUpdate = React.useCallback((update: {layout_mode: number}) => {
+ ...
+ }, []);
+
+ React.useEffect(() => {
+ discordSdk.subscribeToLayoutModeUpdatesCompat(handleLayoutModeUpdate);
+ return () => {
+ discordSdk.unsubscribeFromLayoutModeUpdatesCompat(handleLayoutModeUpdate);
+ };
+ }, [handleLayoutModeUpdate]);
+}
+```
+
+---
+
+### Activity Proxy Considerations
+
+All network traffic is routed through the Discord Proxy for various security reasons. The proxy does not support mapping targets to specific ports. Any mapping to specific ports will have to be handled by your application.
+
+Under the hood we utilize Cloudflare Workers, which brings some restrictions, outlined below.
+
+#### Supported Ports
+
+See the full list of supported ports for network traffic, as listed in [Cloudflare's Docs](https://developers.cloudflare.com/fundamentals/reference/network-ports/#network-ports-compatible-with-cloudflares-proxy).
+
+#### WebTransport
+
+While we currently only support websockets, we're working with our upstream providers to enable WebTransport.
+
+#### WebRTC
+
+WebRTC is not supported.
+
+Other guides are available in this [Networking](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/networking) section for using external network resources and constructing a full url versus relative urls.
+
+---
+
+### 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
+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 |
+
+---
+
+### 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](#DOCS_ACTIVITIES_DEVELOPMENT_GUIDES/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, 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
+import {DiscordSDK} from '@discord/embedded-app-sdk';
+const discordSdk = new DiscordSDK(YOUR_APP_ID);
+const isProd = process.env.NODE_ENV === 'production'; // Actual dev/prod env check may vary for you
+
+async function setupApp() {
+ if (isProd) {
+ discordSdk.patchUrlMappings([{prefix: '/foo', target: 'foo.com'}]);
+ }
+ // start app initialization after this....
+}
+```
+
+> info
+> 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.
+
+---
+
+### 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](activities/join-application.png)
+
+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
+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
+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.GetApplicationInstanceConnectedParticipantsResponse) {
+ // 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](https://discord.com/developers/docs/reference#image-formatting-cdn-endpoints).
+
+Here's a basic example for retrieving a user's avatar and username
+
+```javascript
+// We'll be referencing the user object returned from authenticate
+const {user} = await DiscordRPC.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 = Math.abs(Number(user.id) >> 22) % 6;
+ avatarSrc = `https://cdn.discordapp.com/embed/avatars/${defaultAvatarIndex}.png`
+}
+
+const username = user.global_name ?? `${user.username}#${user.discriminator}`;
+
+// Then in your HTML/JSX/etc...
+
+
{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 avater/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
+// We'll be referencing the user object returned from authenticate
+const {user} = await DiscordRPC.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/${DiscordRPC.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/${DiscordRPC.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 = Math.abs(Number(user.id) >> 22) % 6;
+ 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
+
+---
+
+### 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.
+
+> info
+> 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` 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
+
+---
+
+### 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 a content hash and manifest](https://webpack.js.org/guides/caching/) as a part of the build process.
+
+----
+
+### 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](https://discord.com/developers/docs/topics/rate-limits).
+
+See [this implementation in the Activity Starter project](https://github.com/discord/embedded-app-sdk/blob/main/examples/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
+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
+ ...
+ }
+}
+```
\ No newline at end of file
diff --git a/docs/activities/How_Activities_Work.md b/docs/activities/How_Activities_Work.md
new file mode 100644
index 0000000000..04778881a0
--- /dev/null
+++ b/docs/activities/How_Activities_Work.md
@@ -0,0 +1,66 @@
+# How Activities Work
+
+> preview
+> Creating Activities is currently available as a [Public Developer Preview](#DOCS_ACTIVITIES_OVERVIEW/public-developer-preview).
+
+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](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK). Our [Sample Projects](#DOCS_ACTIVITIES_OVERVIEW/sample-projects) provide practical examples of how to implement these features.
+
+### 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](#DOCS_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
+
+> info
+> Below is a minimal example of setting up the SDK. Please see our [Sample Projects](#DOCS_ACTIVITIES_OVERVIEW/sample-projects) for more complete sample applications.
+
+```javascript
+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('/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/embedded-app-flow-diagram.svg)
\ No newline at end of file
diff --git a/docs/activities/Overview.mdx b/docs/activities/Overview.mdx
new file mode 100644
index 0000000000..2c4741ade4
--- /dev/null
+++ b/docs/activities/Overview.mdx
@@ -0,0 +1,71 @@
+# Discord Activities
+
+> preview
+> Creating Activities is currently available as a [Public Developer Preview](#DOCS_ACTIVITIES_OVERVIEW/public-developer-preview).
+
+![Building Discord Activities](activities/activities-hero.png)
+
+### The channel is your canvas
+
+Activities are multiplayer games and social experiences in Discord. Under the hood, an Activity is a web application hosted in an iframe within the Discord client. Once a user connects to your Activity, your app can request information using Discord APIs and gateway events to build rich, interactive experiences for your players.
+
+Whether you're developing a multiplayer game, a new social experience, or another creative idea, your Activity will be built with the [Embedded App SDK](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK). The 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.
+
+A few examples of Activities built by Discord are [Putt Party](https://support.discord.com/hc/en-us/articles/5101932219671-Putt-Party-FAQ), [Sketch Heads](https://support.discord.com/hc/en-us/articles/4409235005207-Sketch-Heads-FAQ), and [Jamspace Whiteboard](https://support.discord.com/hc/en-us/articles/14042410493847-Jamspace-Whiteboard-FAQ).
+
+The Embedded App SDK uses the RPC API to handle the communication between Discord and your Activity. These guides will help you start building the next big thing on Discord.
+
+
+
+ Learn more about how Activities are run in Discord.
+
+
+ Get started building an Activity using the Embedded App SDK.
+
+
+ Explore common development patterns to make building Activities simpler.
+
+
+
+---
+
+## Sample Projects
+
+We've published some sample apps on [GitHub](https://github.com/discord/embedded-app-sdk/tree/main/examples) to help you get started building quickly and learn from common development patterns.
+
+
+
+ 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 example uses React Colyseus to demonstrate state management in a multiplayer experience.
+
+
+ This reference example demonstrates an Activity using a nested framework like a game engine.
+
+
+
+---
+
+## Public Developer Preview
+
+Building Activities with the Embedded App SDK is currently in developer preview. During this initial preview, developers will find some limitations that will be removed as we continue to release developer features and functionality for Activities.
+
+Current limitations include:
+- Activities will only be playable in servers with 25 users or less
+- In-App Purchases (IAP) are possible within Activities but not yet available to developers in this Developer Preview
+- Activities cannot become Verified in this Developer Preview
+- Existing Verified Apps cannot add Activities during this Developer Preview
+
+---
+
+## Support & Feedback
+During this Developer Preview, you can get support and report issues:
+
+- Come find us in the `#activities-dev-help` channel in the [Discord Developers Server](https://discord.gg/discord-developers)
+- Check out the [SDK Release Log](https://github.com/discord/embedded-app-sdk/releases) on GitHub to follow along with updates
+- Report issues in the [Embedded App SDK Github repo](https://github.com/discord/embedded-app-sdk)
+- Reach out to our [Developer Support](https://dis.gd/developer-activities) team if you have any questions about the SDK
\ No newline at end of file
diff --git a/docs/developer_tools/Embedded_App_SDK.md b/docs/developer_tools/Embedded_App_SDK.md
new file mode 100644
index 0000000000..850983e2e6
--- /dev/null
+++ b/docs/developer_tools/Embedded_App_SDK.md
@@ -0,0 +1,789 @@
+# Embedded App SDK Reference
+
+> preview
+> Creating Activities is currently available as a [Public Developer Preview](#DOCS_ACTIVITIES_OVERVIEW/public-developer-preview).
+
+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](#DOCS_ACTIVITIES_BUILDING_AN_ACTIVITY) tutorial or explore our [Sample Projects](#DOCS_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
+import { DiscordSDK } from "@discord/embedded-app-sdk";
+
+const discordSdk = new DiscordSDK(DISCORD_CLIENT_ID);
+```
+
+---
+
+## SDK Methods
+
+| Name | Description |
+|-------------------------------------------------------------------|-------------------------------------------------------------------------|
+| [ready](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/ready) | Resolves when your app has successfully connected to the Discord client |
+| [subscribe](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/subscribe) | Subscribe to an Embedded App SDK Event |
+| [unsubscribe](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/unsubscribe) | Unsubscribe to an Embedded App SDK Event |
+
+### ready()
+
+Resolves when your app has successfully connected to the Discord client.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ✅ | ✅ | ✅ |
+
+#### Required Scopes
+
+No scopes required
+
+#### SDK Usage
+
+```js
+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](#DOCS_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.
+
+#### Usage
+
+```js
+await discordSdk.subscribe("SDK_EVENT_NAME", eventHandler, args);
+```
+
+---
+
+### unsubscribe()
+
+Used to unsubscribe to [SDK Events](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/sdk-events) that your app has already subscribed to.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ✅ | ✅ | ✅ |
+
+#### Required Scopes
+
+No scopes required
+
+#### Usage
+
+```js
+await discordSdk.unsubscribe("SDK_EVENT_NAME");
+```
+
+---
+
+## 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](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/authenticate) | Authenticate an existing client with your app |
+| [authorize](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/authorize) | Authorize a new client with your app |
+| [captureLog](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/capturelog) | Forward logs to your own logger |
+| [encourageHardwareAcceleration](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/encouragehardwareacceleration) | Presents a modal dialog to allow enabling of hardware acceleration |
+| [getChannel](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/getchannel) | Returns information about the channel, per the channel_id |
+| [getChannelPermissions](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/getchannelpermissions) | Returns permissions for the current user in the currently connected channel |
+| [getEntitlements](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/getentitlements) | Not available during Developer Preview |
+| [getInstanceConnectedParticipants](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/getinstanceconnectedparticipants) | Returns all participants connected to the instance |
+| [getPlatformBehaviors](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/getplatformbehaviors) | Returns information about supported platform behaviors |
+| [getSkus](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/getskus) | Not available during Developer Preview |
+| [initiateImageUpload](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/initiateimageupload) | Presents the file upload flow in the Discord client |
+| [openExternalLink](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/openexternallink) | Allows for opening an external link from within the Discord client |
+| [openInviteDialog](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/openinvitedialog) | Presents a modal dialog with Channel Invite UI without requiring additional OAuth scopes |
+| [openShareMomentDialog](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/opensharemomentdialog) | Presents a modal dialog to share media to a channel or DM |
+| [setActivity](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/setactivity) | Modifies how your activity's rich presence is displayed in the Discord client |
+| [setOrientationLockState](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/setorientationlockstate) | Set options for orientation and picture-in-picture (PIP) modes |
+| [startPurchase](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/startpurchase) | Not available during Developer Preview |
+| [userSettingsGetLocale](#DOCS_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
+
+#### Usage
+
+```js
+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
+
+#### Usage
+
+```js
+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
+
+#### Usage
+
+```js
+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
+
+#### Usage
+
+```js
+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.
+
+#### Usage
+```js
+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
+
+#### Usage
+
+```js
+await discordSdk.commands.getChannelPermissions();
+```
+
+---
+
+### getEntitlements()
+
+> preview
+> Coming soon! Not available during Developer Preview
+
+---
+
+### getInstanceConnectedParticipants()
+
+Returns all participants connected to the instance.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ✅ | ✅ | ✅ |
+
+#### Required Scopes
+
+No scopes required
+
+#### Usage
+
+```js
+await discordSdk.commands.getInstanceConnectedParticipants();
+```
+
+---
+
+### getPlatformBehaviors()
+
+Returns information about supported platform behaviors.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ✅ | ✅ | ✅ |
+
+#### Required Scopes
+
+No scopes required
+
+#### Usage
+
+```js
+await discordSdk.commands.getPlatformBehaviors();
+```
+
+---
+
+### getSkus()
+
+> preview
+> Coming soon! Not available during Developer Preview
+
+---
+
+### initiateImageUpload()
+
+Presents the file upload flow in the Discord client.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ✅ | ✅ | ✅ |
+
+#### Required Scopes
+
+No scopes required
+
+#### Usage
+
+```js
+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
+
+#### Usage
+
+```js
+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
+
+#### Usage
+
+```js
+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
+
+#### Usage
+
+```js
+await discordSdk.commands.openShareMomentDialog({
+ mediaUrl: 'DISCORD_CDN_URL'
+});
+```
+
+---
+
+### setActivity()
+
+Modifies how your activity's rich presence is displayed in the Discord client.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ✅ | ✅ | ✅ |
+
+#### Required Scopes
+
+- rpc.activities.write
+
+#### Usage
+
+```js
+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
+
+#### Usage
+
+```js
+await discordSdk.commands.setConfig({
+ user_interactive_pip: true
+})
+```
+
+---
+
+### setOrientationLockState()
+
+Locks the application to specific orientations in each of the supported layout modes.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ⛔️ | ✅ | ✅ |
+
+#### Required Scopes
+
+- guilds.members.read
+
+#### Usage
+
+```js
+await discordSdk.commands.commands.setOrientationLockState({
+ lock_state: 'landscape',
+ picture_in_picture_lock_state: 'landscape',
+ grid_lock_state: 'unlocked'
+});
+```
+
+---
+
+### startPurchase()
+
+> preview
+> Coming soon! Not available during Developer Preview
+
+---
+
+### userSettingsGetLocale()
+
+Returns the current user's locale.
+
+#### Supported Platforms
+| Web | iOS | Android |
+|-----|-----|---------|
+| ✅ | ✅ | ✅ |
+
+#### Required Scopes
+
+- identify
+
+#### Usage
+
+```js
+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](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/ready) | non-subscription event sent immediately after connecting, contains server information |
+| [ERROR](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/error) | non-subscription event sent when there is an error, including command responses |
+| [VOICE_STATE_UPDATE](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/voicestateupdate) | sent when a user's voice state changes in a subscribed voice channel (mute, volume, etc.) |
+| [SPEAKING_START](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/speakingstart) | sent when a user in a subscribed voice channel speaks |
+| [SPEAKING_STOP](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/speakingstop) | sent when a user in a subscribed voice channel stops speaking |
+| [ACTIVITY_LAYOUT_MODE_UPDATE](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/activitylayoutmodeupdate) | Received when a user changes the layout mode in the Discord client |
+| [ORIENTATION_UPDATE](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/orientationupdate) | Received when screen orientation changes |
+| [CURRENT_USER_UPDATE](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/currentuserupdate) | Received when the current user object changes |
+| [THERMAL_STATE_UPDATE](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/thermalstateupdate) | Received when Android or iOS thermal states are surfaced to the Discord app |
+| [ACTIVITY_INSTANCE_PARTICIPANTS_UPDATE](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/activityinstanceparticipantsupdate) | Received when the number of instance participants changes |
+| [ENTITLEMENT_CREATE](#DOCS_DEVELOPER_TOOLS_EMBEDDED_APP_SDK/entitlementcreate) | Not available during Developer Preview |
+
+
+### READY
+
+Non-subscription event sent immediately after connecting, contains server information.
+
+#### Required Scopes
+
+No scopes required
+
+#### Sample Event Payload
+
+```javascript
+{
+ "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
+{
+ "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
+{
+ "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
+{
+ "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
+{
+ "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
+{
+ "layout_mode": 1
+}
+```
+
+---
+
+### ORIENTATION_UPDATE
+
+Received when screen orientation changes.
+
+#### Required Scopes
+
+No scopes required
+
+#### Sample Event Payload
+
+```javascript
+{
+ "screen_orientation": 1
+}
+```
+
+---
+
+### CURRENT_USER_UPDATE
+
+Received when the current user object changes.
+
+#### Required Scopes
+
+- identify
+
+#### Sample Event Payload
+
+```javascript
+{
+ "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
+}
+```
+
+---
+
+### 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
+{
+ thermal_state: 0
+}
+```
+
+---
+
+### ACTIVITY_INSTANCE_PARTICIPANTS_UPDATE
+
+Received when the number of instance participants changes.
+
+#### Required Scopes
+
+No scopes required
+
+#### Sample Event Payload
+
+```javascript
+{
+ "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
+ }
+ ]
+}
+```
+
+---
+
+### ENTITLEMENT_CREATE
+
+> preview
+> Coming soon! Not available during Developer Preview
\ No newline at end of file
diff --git a/images/activities/activities-hero.png b/images/activities/activities-hero.png
new file mode 100644
index 0000000000..7c62e3f9d2
Binary files /dev/null and b/images/activities/activities-hero.png differ
diff --git a/images/activities/application-test-mode-prod.gif b/images/activities/application-test-mode-prod.gif
new file mode 100644
index 0000000000..d765a258cb
Binary files /dev/null and b/images/activities/application-test-mode-prod.gif differ
diff --git a/images/activities/bobble-bash.png b/images/activities/bobble-bash.png
new file mode 100644
index 0000000000..3d0b67e526
Binary files /dev/null and b/images/activities/bobble-bash.png differ
diff --git a/images/activities/bobble-league.png b/images/activities/bobble-league.png
new file mode 100644
index 0000000000..a23a1ada86
Binary files /dev/null and b/images/activities/bobble-league.png differ
diff --git a/images/activities/chess-victory.png b/images/activities/chess-victory.png
new file mode 100644
index 0000000000..989999a8e8
Binary files /dev/null and b/images/activities/chess-victory.png differ
diff --git a/images/activities/debug-logs-filtering.gif b/images/activities/debug-logs-filtering.gif
new file mode 100644
index 0000000000..534bf60154
Binary files /dev/null and b/images/activities/debug-logs-filtering.gif differ
diff --git a/images/activities/default_orientation_lock_state.png b/images/activities/default_orientation_lock_state.png
new file mode 100644
index 0000000000..da92fe9d89
Binary files /dev/null and b/images/activities/default_orientation_lock_state.png differ
diff --git a/images/activities/developer-mode.gif b/images/activities/developer-mode.gif
new file mode 100644
index 0000000000..e60333424f
Binary files /dev/null and b/images/activities/developer-mode.gif differ
diff --git a/images/activities/discord-activities.png b/images/activities/discord-activities.png
new file mode 100644
index 0000000000..1a5a12b561
Binary files /dev/null and b/images/activities/discord-activities.png differ
diff --git a/images/activities/eights.png b/images/activities/eights.png
new file mode 100644
index 0000000000..07bfb3525d
Binary files /dev/null and b/images/activities/eights.png differ
diff --git a/images/activities/embedded-app-flow-diagram.svg b/images/activities/embedded-app-flow-diagram.svg
new file mode 100644
index 0000000000..6e16b84b0c
--- /dev/null
+++ b/images/activities/embedded-app-flow-diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/images/activities/encourage-hardware-acceleration-modal.png b/images/activities/encourage-hardware-acceleration-modal.png
new file mode 100644
index 0000000000..a0dec6b4c5
Binary files /dev/null and b/images/activities/encourage-hardware-acceleration-modal.png differ
diff --git a/images/activities/external-link-modal.png b/images/activities/external-link-modal.png
new file mode 100644
index 0000000000..df3a4e38e0
Binary files /dev/null and b/images/activities/external-link-modal.png differ
diff --git a/images/activities/getting-started-activities.png b/images/activities/getting-started-activities.png
new file mode 100644
index 0000000000..ad8e5cc7a5
Binary files /dev/null and b/images/activities/getting-started-activities.png differ
diff --git a/images/activities/invite-dialog.png b/images/activities/invite-dialog.png
new file mode 100644
index 0000000000..2d6cd6888c
Binary files /dev/null and b/images/activities/invite-dialog.png differ
diff --git a/images/activities/join-application.png b/images/activities/join-application.png
new file mode 100644
index 0000000000..b6ef7fca77
Binary files /dev/null and b/images/activities/join-application.png differ
diff --git a/images/activities/new-app.png b/images/activities/new-app.png
new file mode 100644
index 0000000000..9f3c1f5212
Binary files /dev/null and b/images/activities/new-app.png differ
diff --git a/images/activities/oauth-flow-diagram.svg b/images/activities/oauth-flow-diagram.svg
new file mode 100644
index 0000000000..6ce500a5a3
--- /dev/null
+++ b/images/activities/oauth-flow-diagram.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/images/activities/oauth2-details.png b/images/activities/oauth2-details.png
new file mode 100644
index 0000000000..dda8689f1b
Binary files /dev/null and b/images/activities/oauth2-details.png differ
diff --git a/images/activities/oauth2-redirect.png b/images/activities/oauth2-redirect.png
new file mode 100644
index 0000000000..c7f35fbc74
Binary files /dev/null and b/images/activities/oauth2-redirect.png differ
diff --git a/images/activities/share-moment-dialog-example.png b/images/activities/share-moment-dialog-example.png
new file mode 100644
index 0000000000..4f695d9e89
Binary files /dev/null and b/images/activities/share-moment-dialog-example.png differ
diff --git a/images/activities/start-activity.png b/images/activities/start-activity.png
new file mode 100644
index 0000000000..6e19af0a3e
Binary files /dev/null and b/images/activities/start-activity.png differ
diff --git a/images/activities/supported-platforms.png b/images/activities/supported-platforms.png
new file mode 100644
index 0000000000..90d969cbed
Binary files /dev/null and b/images/activities/supported-platforms.png differ
diff --git a/images/activities/tutorial-auth.png b/images/activities/tutorial-auth.png
new file mode 100644
index 0000000000..e0f117e5c6
Binary files /dev/null and b/images/activities/tutorial-auth.png differ
diff --git a/images/activities/tutorial-channel-name.png b/images/activities/tutorial-channel-name.png
new file mode 100644
index 0000000000..c85c9644ec
Binary files /dev/null and b/images/activities/tutorial-channel-name.png differ
diff --git a/images/activities/tutorial-hero.png b/images/activities/tutorial-hero.png
new file mode 100644
index 0000000000..d9281681d0
Binary files /dev/null and b/images/activities/tutorial-hero.png differ
diff --git a/images/activities/tutorial-launched.png b/images/activities/tutorial-launched.png
new file mode 100644
index 0000000000..b7a16bd430
Binary files /dev/null and b/images/activities/tutorial-launched.png differ
diff --git a/images/activities/url-mapping-do.png b/images/activities/url-mapping-do.png
new file mode 100644
index 0000000000..3511e2743f
Binary files /dev/null and b/images/activities/url-mapping-do.png differ
diff --git a/images/activities/url-mapping-dont.png b/images/activities/url-mapping-dont.png
new file mode 100644
index 0000000000..a7a3de4a01
Binary files /dev/null and b/images/activities/url-mapping-dont.png differ
diff --git a/images/activities/url-mapping-tutorial.png b/images/activities/url-mapping-tutorial.png
new file mode 100644
index 0000000000..997d9a8f5d
Binary files /dev/null and b/images/activities/url-mapping-tutorial.png differ