Ludicord
Guide 04 · Start here

Discord setup

Configure OAuth2, Activities, URL mappings, and a safe local development origin.

Ludicord 3.1.0Public source 20c4889
Launch mappingOne public origin reaches one local Activity
Framework managed
DDiscordLaunches the Activity
URL mappingForwards the configured origin
LLudicordCompiles before connecting

A browser preview proves that React and routing compile. A real Discord launch proves that OAuth2, the Embedded App SDK, URL mappings, and Activity context are connected.

#Create the Discord application

Open the Discord Developer Portal and create an application. Record these values:

Portal valueLudicord environment variable
Application IDLUDICORD_DISCORD_CLIENT_ID
Client SecretLUDICORD_DISCORD_CLIENT_SECRET
Public KeyLUDICORD_DISCORD_PUBLIC_KEY
Bot token, when requiredLUDICORD_DISCORD_BOT_TOKEN

The Application ID may be used by client code. Every other credential in this table is server-only.

#Enable Activities

In the application's Activities settings, enable the Activity and configure a launch entry point. Add the OAuth2 scopes required by your features. The generated project starts with identify and guilds.

ludicord.config.mjsjs
1import { defineConfig } from "ludicord/config";
2
3export default defineConfig({
4 discord: {
5 clientId: process.env.LUDICORD_DISCORD_CLIENT_ID,
6 scopes: ["identify", "guilds"],
7 auth: { required: true },
8 },
9});

Request the smallest scope set your Activity needs. A user can decline consent, so keep app/auth/denied.tsx clear and recoverable.

#Expose local development over HTTPS

Discord must reach your local Ludicord server through a public HTTPS hostname. Start npm run dev, then create a tunnel with a provider such as Cloudflare Tunnel.

Terminalbash
1cloudflared tunnel --url http://localhost:3000

The tunnel prints a hostname similar to example-name.trycloudflare.com. Keep the development server and tunnel running together.

#Configure the URL mapping

In Activities → URL Mappings, map the root prefix to the tunnel hostname:

PrefixTarget
/example-name.trycloudflare.com

Enter the hostname without https://. The root mapping must reach the same Ludicord origin because the Activity shell, /_ludicord/auth, /api/*, assets, and /ws/* are designed to work together.

#Why OAuth2 uses 127.0.0.1

Discord does not load the public tunnel as an ordinary top-level website. It places the mapped Activity inside its sandbox and proxies requests through a supported local-looking origin. That is why Discord's Activity OAuth2 documentation and redirect flow use a URL based on 127.0.0.1.

This does not mean Discord is trying to contact the player's own development server. The URL is part of Discord's embedded proxy model. Your URL mapping still decides which public HTTPS hostname receives the request.

iNote

Important: Do not replace Ludicord's Activity OAuth redirect with the tunnel hostname just because the tunnel is public. Configure the redirect expected by Discord's Activities flow and let the mapping proxy requests to Ludicord.

#Launch and verify

Install the application in a test server, join a supported voice or text channel, and launch the Activity. Confirm these signals in order:

  1. The Activity shell loads without a host or CSP error.
  2. Discord authorization appears when required.
  3. The signed-in user is available.
  4. Guild and channel data match the place where the Activity launched.
  5. /api/hello returns a session-aware response.
  6. The audience WebSocket reaches open.

#Common setup failures

SymptomCheck
Blank ActivityRoot URL mapping, tunnel status, allowed host, browser console
OAuth2 redirect mismatchExact Discord Activity redirect and application ID
User available but guild missingLaunch context and granted scopes
API returns 401Session secret, cookies, completed SDK authentication
WebSocket never opensHTTPS mapping, /ws path, session cookie, proxy upgrade support

#Next step

With Discord connected, build the persistent shell and screens in Pages and embeds.