Skip to main content

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.

Dev and test are internal

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​

SurfaceURL
Studio (sign up, create app, wallet)https://studio.crowdedkingdoms.com
GraphQL API — management AND game, one endpointhttps://ck.prod.crowdedkingdoms.com/graphql
WebSocket subscriptions — same originwss://ck.prod.crowdedkingdoms.com/graphql
Schema (SDL)/schema/game-api.graphql on this site
There is one endpoint, not two

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:

  1. 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.
  2. 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.

  1. Open https://studio.crowdedkingdoms.com
  2. 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.
  3. Create an org if prompted, then run Get started to register your app — see Create your first app
  4. When create completes, runtimeStatus is active and gameApiUrl points 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 /graphql for HTTP; the WebSocket uses the same host with wss://.
  • Prefer mintAppToken return values for gameApiUrl / gameApiWsUrl over 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:

Verify connectivity (smoke checklist)​

Goal: platformConfig → sign in → create app → mint app token → gameplay.

  1. platformConfig.sharedGameApiUrl returns a URL (no token needed).
  2. Sign in → create shared app → confirm app.runtimeStatus === "active" and gameApiUrl set.
  3. mintAppToken → receive the app-scoped token and the app's datacenter URLs.
  4. gameClientBootstrap(appId) against those URLs (Bearer = app token) → 200.
  5. connectUdpProxy → connected: true.
  6. sendActorUpdate / sendClientEvent → notifications (not UNAUTHORIZED).

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.