The five problems of any online game
- Identity — who is this player, and is it the same one as yesterday?
- Matchmaking — which players share a session?
- Transport — how does data get from one browser to another quickly?
- Authority — who decides the score, and how do you stop a modified client?
- Persistence — what survives the match: stats, items, leaderboards?
Traditionally each of those is a server you write. Below, each one is a single call.
Step 1 — Get keys
curl -X POST https://multiplayerapi.com/v1/games \
-H 'Content-Type: application/json' \
-d '{"name":"My Game","preset":"realtime_arena"}'Keep mp_pk_… for the client. Store mp_sk_… somewhere safe: it is shown once and must never ship in a client.
Step 2 — Identity: guest login
const mp = new Multiplayer({ key: 'mp_pk_...', displayName: 'Alice' });
await mp.login(); // resumes a stored session, or creates an instant guest accountRequiring a sign-up form before the first match loses most players. Guests get stats, inventory and a leaderboard place immediately and can upgrade() to a username and password later without losing anything.
Step 3 — Matchmaking
const room = await mp.quickmatch({ mode: 'ffa', max_players: 8 });
// or private games with friends:
const priv = await mp.create({ max_players: 4 }); // share priv.code
await mp.join('B2K2D3');quickmatch joins the best matching room or creates one. Filter with free-form meta such as { map: 'desert' }.
Step 4 — Transport: pick the right channel
| Channel | Call | Delivery | Use it for |
|---|---|---|---|
| Direct | room.send(data) | peer-to-peer, best effort, zero server cost | positions, aim, animation |
| State | room.set(path, value) | server-validated, kept for the match, reaches late joiners | health, score, whose turn |
| Events | room.emitEvent(topic, data) | ordered, guaranteed, not persisted | chat, rematch, one-shots |
room.on('peer', (p, from) => others[from] = p);
setInterval(() => room.send({ x: me.x, y: me.y }), 50);
room.mine('hp', 100); // writes players.<me>.hp
room.state.watch('players.*.hp', drawHp);
room.emitEvent('chat', { text: 'gg' });Step 5 — Authority and persistence
Declare rules once; the server enforces them on every sync:
{
"state": {
"players.$self.hp": { "write": "self", "type": "int", "min": 0, "max": 100 },
"players.$self.score": { "write": "host", "type": "int", "monotonic": "up" }
}
}Then submit scores with mp.submitScore('arena', score) and read mp.leaderboard('arena', { period: 'weekly' }). Results that grant rewards can require peer attestation so a lone host cannot award itself anything.
Hosting the game
Your game is now a static site. Put it on GitHub Pages, Netlify, Vercel, Cloudflare Pages or itch.io. In production, list those domains in the game's origins so other sites cannot use your public key from a browser.
Engine-specific versions of this guide: Phaser, Three.js, PixiJS, vanilla JavaScript.
Do I need a server to make a multiplayer browser game?
You need server infrastructure — signaling, relay, accounts, validation — but you do not need to run it yourself. A hosted multiplayer API provides it while your game stays static.
Should I use WebSockets or WebRTC for a browser game?
WebRTC data channels connect players directly, which is faster and costs no server bandwidth. WebSockets go through a server. The best setup uses WebRTC with a server relay fallback — which the SDK handles automatically.
Make your game online today
Free sandbox keys in one call, no account and no card. $19.99/month when you ship, for every game you make.
Free sandbox · $19.99/mo to go live · cancel anytime