Connecting game clients
Build and test against production: sign up in Studio, create an app on the shared platform, and connect to the shared Game API. The free tier covers early development; Shared environment & billing explains what is billed beyond it.
Crowded Kingdoms also runs dev and test environments. They are internal: only
Crowded Kingdoms staff and approved partners can sign in there, and any other account
is refused with TIER_ACCESS_REQUIRED.
Everything on this site works on production.
Hosts
| Surface | URL |
|---|---|
| Studio (sign up, create app, wallet) | https://studio.crowdedkingdoms.com |
| GraphQL API — management AND game, one endpoint | https://ck.prod.crowdedkingdoms.com/graphql |
| WebSocket subscriptions — same origin | wss://ck.prod.crowdedkingdoms.com/graphql |
| Schema (SDL) | /schema/game-api.graphql on this site |
Management and game are two surfaces of the same origin. Do not set
managementUrl; it was removed in CrowdyJS 14.
Production serves no GraphQL playground and does not answer introspection. Point any GraphQL client at the endpoint above and load the published schema, or browse it in the Game API reference.
Programmatic discovery (no auth required):
query {
platformConfig {
sharedGameApiUrl # https://ck.prod.crowdedkingdoms.com
sharedGameApiWsUrl # wss://ck.prod.crowdedkingdoms.com
freeAppsPerOrg # default 3
}
}
After you create an app, confirm routing:
query {
app(appId: "<your-app-id>") {
appId
deploymentTarget # "shared"
runtimeStatus # "active"
gameApiUrl
}
}
Prefer what the API hands you over a template. mintAppToken returns
gameApiUrl and gameApiWsUrl, which name the datacenter holding your app. Use
those values rather than a hard-coded host.
Two tokens (required)
One endpoint serves everything, but Crowded Kingdoms separates identity from gameplay by credential:
- Identity — sign-in (email + password, magic link, or social/OIDC), org and app operations. Sign-in returns an identity session token, and that token cannot drive gameplay.
- Gameplay — chunks, voxels, actors, UDP proxy subscriptions, and world
mutations. Needs an app-scoped token minted from the session token
(
mintAppToken, or the portal PKCE flow), not the login token.
See Client Workflow and Portals & app-scoped tokens.
Flow: sign in → create app (or use existing) → mint an app-scoped token → make gameplay calls with that token, against the URLs the mint returned.
Create your account and app
You do not need a shared admin account. Sign in with email and a password, a magic link, or a social provider.
- Open https://studio.crowdedkingdoms.com
- Sign in with a magic link (enter your work email; the account is created on first sign-in) or a social provider, then set your gamertag. Email + password also works.
- Create an org if prompted, then run Get started to register your app — see Create your first app
- When create completes,
runtimeStatusisactiveandgameApiUrlpoints at the shared endpoint
Account basics: Account and org basics.
Find your User ID
To join an existing studio org, share your User ID with an org owner.
Find it under Account → Profile
(https://studio.crowdedkingdoms.com/account)
or query me { userId email } with your session token.
Configure your client
Example after you create your own app (replace appId with your value):
ApiHttpUrl=https://ck.prod.crowdedkingdoms.com/graphql
ApiWsUrl=wss://ck.prod.crowdedkingdoms.com/graphql
AppId=<your-app-id>
URL rules:
- Include
/graphqlfor HTTP; the WebSocket uses the same host withwss://. - Prefer
mintAppTokenreturn values forgameApiUrl/gameApiWsUrlover hard-coding: an app lives in one datacenter, and those values point at it.
CrowdyJS
import { createCrowdyClient, BrowserLocalStorageTokenStore } from '@crowdedkingdoms/crowdyjs';
// Identity client — holds the session token (management plane).
const identity = createCrowdyClient({
httpUrl: 'https://ck.prod.crowdedkingdoms.com/graphql',
tokenStore: new BrowserLocalStorageTokenStore('crowdyjs:session'),
});
// Sign in. Email + password works everywhere; magic link needs email
// delivery, and social needs configured provider credentials.
await identity.auth.login({ email: 'you@example.com', password });
// Mint an app-scoped token for your app, then drive gameplay from a per-game client.
const appToken = await identity.portal.mintAppToken('<your-app-id>');
// gameApiUrl / gameApiWsUrl point at the datacenter holding this app.
const game = createCrowdyClient({
httpUrl: appToken.gameApiUrl ?? 'https://ck.prod.crowdedkingdoms.com/graphql',
wsUrl: appToken.gameApiWsUrl ?? 'wss://ck.prod.crowdedkingdoms.com/graphql',
tokenStore: new BrowserLocalStorageTokenStore('crowdyjs:app:<your-app-id>'),
});
game.setToken(appToken.token);
A browser game published on its own domain signs players in through Studio's hosted
sign-in (portal.signIn) rather than a login form of its own; see
Portals & app-scoped tokens.
Full SDK guide: CrowdyJS. Routing details: Shared environment routing.
Unreal and other native clients
Use the same endpoint and the same token model: sign in for the identity session token, mint an app-scoped token for your app, then use that token for gameplay. Browsers typically use the GraphQL UDP proxy; native clients can use the Replication API, signing UDP packets with the app-scoped token after server assignment. In the Unreal SDK, choose Production in the Backend selector. Unreal SDK docs: Unreal SDK intro.
Org membership
Create your own org through Get started, or join an existing studio:
- Org owners invite members by User ID — see Account and org basics.
Verify connectivity (smoke checklist)
Goal: platformConfig → sign in → create app → mint app token → gameplay.
platformConfig.sharedGameApiUrlreturns a URL (no token needed).- Sign in → create shared app → confirm
app.runtimeStatus === "active"andgameApiUrlset. mintAppToken→ receive the app-scoped token and the app's datacenter URLs.gameClientBootstrap(appId)against those URLs (Bearer = app token) → 200.connectUdpProxy→connected: true.sendActorUpdate/sendClientEvent→ notifications (notUNAUTHORIZED).
Browser path: GraphQL UDP proxy. Connection overview: Connecting to your app.
If gameplay fails, confirm you are sending an app-scoped token for this
app (the identity session token is rejected) and that it has not expired —
rotate it with refreshAppToken (or re-mint) on a TOKEN_EXPIRED error.
Related guides
- Best practices — authority in your server code on ck-exec, tokens, errors
- Create your first app — register an app on the shared platform
- Connecting to your app — endpoints and client configuration
- Shared environment & billing — free tier, wallet, runtime status
- Management API — authentication and tokens
- Game API — world and gameplay surface
- Client Workflow — platform map