Raw socket client
The engine speaks plain Socket.IO. Everything on the per-game pages that follow assumes you've read this page first β the connection handshake, reconnection behavior, and one specific footgun are the same across every game.
@beta-gamer/react) that wraps all of this. It's not optimized for the current hosted-matchmaking architecture yet, so this reference documents the protocol directly β enough to build a fully working client without it. Once the SDK catches up, this page doesn't go away; it becomes the reference the SDK itself is built on top of.Connecting
Each game has its own Socket.IO namespace. Connect with a sessionToken from session creation β never an API key.
import { io } from 'socket.io-client';
const socket = io('https://api.beta-gamer.com/checkers', {
auth: { token: sessionToken },
autoConnect: false, // see the Strict Mode warning below before removing this
});
socket.connect();What the server checks, in order
| Check | Rejected with |
|---|---|
| Token present and a string | unauthorized: missing session token |
| Token verifies (not expired, valid signature) | unauthorized: invalid or expired session token |
| Tokenβs game claim matches this namespace | unauthorized: token issued for a different game |
| Token carries a playerId claim | unauthorized: token missing playerId claim |
A token minted for /checkers will not authenticate against /pool β each token is scoped to one game. On rejection, the server calls next(new Error(...)), which surfaces client-side as a connect_error event with that message.
socket.on('connect_error', (err) => {
console.error('Connection rejected:', err.message);
});The Strict Mode footgun
useEffect with no guard, you get two real connections β the first one immediately orphaned, its variables still referenced by stale closures. Symptoms: a shot or move that silently does nothing, or fires against a dead connection.The fix that held up under testing β autoConnect: false, deferred connect(), and deliberately no "already initialized" guard:
useEffect(() => {
const s = io('https://api.beta-gamer.com/checkers', {
auth: { token: sessionToken },
autoConnect: false,
});
socketRef.current = s;
s.connect();
return () => { s.disconnect(); };
}, [sessionToken]);isInitialized ref to prevent a "double" connect is exactly backwards β it blocks Strict Mode's second mount from ever creating its socket, leaving only the first, doomed one alive. No guard, autoConnect: false, and cleanup that actually calls disconnect() is the whole fix.Disconnection and reconnection
A dropped connection doesn't end the match immediately. The server holds the player's seat open for a grace window β reconnecting with the same sessionToken within that window resumes the game in place.
| Game | Reconnect window |
|---|---|
| Pool | 60 seconds |
| Checkers / Tic-tac-toe / Connect 4 / Fight Arena / Ludo | Varies by game β see each gameβs own page |
// Reconnect with the same token
socket.on('connect', () => {
socket.emit('game:reconnect', { roomId, playerId });
});
socket.on('game:reconnected', (state) => {
// full current game state β rehydrate your UI from this
});game:reconnect event β Pool does; check each game's own events page before assuming this exact shape applies everywhere.Common events, every game
These event names and payloads are shared verbatim β verified identical across all six games' socket handlers, not just similar.
| Event | Direction | Payload |
|---|---|---|
error | server β client | { message: string } |
matchmaking:join | client β server | { username?: string, playerId: string } |
matchmaking:leave | client β server | none |
matchmaking:already_started | server β client | Sent instead of matching you again if a match is already underway. |
game:started | server β client | Game-specific shape β see each gameβs own page. Always includes roomId, players, playerId. |
game:over | server β client | Same result shape as the game.ended webhook β see Webhooks. |
Next
Once connected, each game's own page has the exact events, hosted-session properties, and rules you need. Start with whichever game you're building against.