Client SDK
The Client SDK provides everything you need to connect to a Colyseus server from your game or application.
Set Up
The Client instance is your entry point to connect to the server.
import { Client } from "@colyseus/sdk";
const client = new Client("http://localhost:2567");
// ... with full-stack type safety (optional)
import type { server } from "../../server/src/app.config.ts";
const client = new Client<typeof server>("http://localhost:2567");Connecting to Rooms
Once you have a client, you can connect to rooms. Choose the method that best fits your matchmaking needs.
Join or Create (Recommended)
The most common way to connect. Joins an existing room if available, or creates a new one.
client.joinOrCreate (roomName: string, options: any)try {
const room = await client.joinOrCreate("battle", {/* options */});
console.log("joined successfully", room);
} catch (e) {
console.error("join error", e);
}Locked or private rooms are ignored by this method.
Create a New Room
Always creates a new room instance, even if others exist.
client.create (roomName: string, options: any)try {
const room = await client.create("battle", {/* options */});
console.log("joined successfully", room);
} catch (e) {
console.error("join error", e);
}You may dissallow the client from creating rooms. See Matchmaker → API Restricting the frontend from creating rooms
Join an Existing Room
Joins an existing room by room name. Fails if no room is available.
client.join (roomName: string, options: any)try {
const room = await client.join("battle", {/* options */});
console.log("joined successfully", room);
} catch (e) {
console.error("join error", e);
}Locked or private rooms are ignored by this method.
Join by Room ID
Joins a specific room by its unique ID. This is useful for invite links or rejoining a specific game. Private rooms can be joined by ID.
client.joinById (roomId: string, options: any)try {
const room = await client.joinById("KRYAKzRo2", {/* options */});
console.log("joined successfully", room);
} catch (e) {
console.error("join error", e);
}Example: Creating an invite link
// Share the room ID with other players
const inviteLink = `https://mygame.com/join?roomId=${room.roomId}`;
// On the receiving end, parse the room ID and join
let roomId = location.href.match(/roomId=([a-zA-Z0-9\-_]+)/)[1];
client.joinById(roomId).then(room => {
// ...
});Consume Seat Reservation
Join a room using a pre-reserved seat.
A “seat reservation” is a token generated by the server that allows a client to join a specific room instance. This is useful for scenarios where you want to control access to rooms, such as private matches or matchmaking systems.
client.consumeSeatReservation (reservation)try {
const room = await client.consumeSeatReservation(reservation);
console.log("joined successfully", room);
} catch (e) {
console.error("join error", e);
}A “seat reservation” can be obtained from the backend using the Match-maker API. See Match-maker API → Reserve Seat For
Send and Receive Messages
Once connected to a room, you can send and receive messages in real-time.
Send Message
Send messages to the room handler. Messages are encoded with MsgPack and can hold any JSON-serializable data.
room.send (type, message)//
// sending message with string type
//
room.send("move", { direction: "left"});
//
// sending message with number type
//
room.send(0, { direction: "left"});Backend: See Room → Message Handling for detailed documentation on receiving messages from the client.
Send Raw Bytes
For custom encoding, send raw byte arrays (numbers from 0 to 255).
room.sendBytes (type, bytes)//
// sending message with number type
//
room.sendBytes(0, [ 172, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33 ]);
//
// sending message with string type
//
room.sendBytes("some-bytes", [ 172, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33 ]);On Message
Listen for messages sent from the server.
room.onMessage("powerup", (message) => {
console.log("message received from server");
console.log(message);
});Backend: To send a message from the server to a client you’ll need to use either client.send() or room.broadcast()
State Synchronization
The room state is automatically synchronized from the server to all connected clients.
Accessing Room State
The room.state property always contains the latest synchronized state from the server.
room.state: anyOn State Change
The onStateChange event fires whenever the server synchronizes state updates.
room.onStateChange.once((state) => {
console.log("this is the first room state!", state);
});
room.onStateChange((state) => {
console.log("the room state has been updated:", state);
});State Sync Callbacks
For better performance and control, listen to specific property changes instead of the entire state.
// get state callbacks handler
const callbacks = Callbacks.get(room);Check out the Client SDK → State Sync Callbacks section for detailed documentation on listening to specific state changes.
Read more about State Sychronization
Connection Lifecycle
Handle the various states of a room connection.
Leaving a Room
Disconnect from the room. Use consented: true (default) for intentional leaves, or false to simulate an unexpected disconnect.
room.leave (consented: boolean)// consented leave
room.leave();
// force unconsented leave
room.leave(false);Backend: Use Room → On Leave to handle client disconnection.
On Leave Event
Triggered when the client leaves the room (either intentionally or due to disconnection).
room.onLeave((code) => {
console.log("client left the room");
});Possible closing codes and their meaning:
1000- Regular socket shutdown- Between
1001and1015- Abnormal socket shutdown - Between
4000and4999- Custom socket close code (See more details)
Automatic Reconnection
The SDK automatically attempts to reconnect when the connection is unexpectedly dropped.
Automatic reconnection only triggers if the room has been connected for at least minUptime milliseconds. This prevents reconnection loops for rooms that fail immediately after joining.
On Drop Event
Triggered when the connection is unexpectedly dropped. The SDK will automatically attempt to reconnect.
room.onDrop((code, reason) => {
console.log("connection dropped, attempting to reconnect...");
console.log("code:", code, "reason:", reason);
});The onDrop event is different from onLeave. While onLeave is triggered when the client intentionally leaves or the connection is permanently closed, onDrop indicates a temporary disconnection where reconnection will be attempted.
Close codes that trigger onDrop:
1005- No status received1006- Abnormal closure1001- Going away4010- May try reconnect
On Reconnect Event
Triggered when the client successfully reconnects after a connection drop. While disconnected, your room.send() calls will be queued and sent to the server when the client reconnects. The maximum number of queued messages is configurable using room.reconnection.maxEnqueuedMessages.
room.onReconnect(() => {
console.log("successfully reconnected to the room!");
});Configuration Options
You may configure the reconnection behavior using room.reconnection.
Reconnection config options
| Option | Default | Description |
|---|---|---|
maxRetries | 15 | Maximum reconnection attempts |
minDelay | 100 | Minimum delay between attempts (ms) |
maxDelay | 5000 | Maximum delay between attempts (ms) |
minUptime | 5000 | Minimum room uptime before reconnection is allowed (ms) |
delay | 100 | Initial delay between attempts (ms) |
maxEnqueuedMessages | 10 | Maximum buffered messages during reconnection |
backoff | exponential | Delay calculation function |
Status properties (read-only)
| Property | Type | Description |
|---|---|---|
isReconnecting | boolean | Whether currently reconnecting |
retryCount | number | Current reconnection attempt count |
enqueuedMessages | number | Buffered messages |
Customizing reconnection behavior:
const room = await client.joinOrCreate("battle");
// Customize reconnection options
room.reconnection.maxRetries = 10;
room.reconnection.maxDelay = 10000; // 10 seconds max delay
room.reconnection.minUptime = 3000; // Allow reconnection after 3 secondsCustom backoff function:
room.reconnection.backoff = (attempt: number, delay: number) => {
return Math.floor(Math.pow(2, attempt) * delay);
};Manual Reconnection
For more control, you can manually reconnect using a cached reconnection token. Because this method returns a new room instance on the client, you must reattach all event listeners to the room after reconnecting.
- You must store/cache the
room.reconnectionTokenfrom an active room connection. - The server needs to call
.allowReconnection()for that client.
client.reconnect (reconnectionToken)try {
const room = await client.reconnect(cachedReconnectionToken);
console.log("joined successfully", room);
} catch (e) {
console.error("join error", e);
}Error Handling
Listen for errors that occur in the room.
room.onError((code, message) => {
console.log("oops, error ocurred:");
console.log(message);
});Removing Listeners
Remove all event listeners from the room.
room.removeAllListeners()Latency & Server Selection
Measure network latency and choose optimal servers for your players.
Measuring Latency
On the Client
Create a temporary connection to measure latency before joining a room.
client.getLatency (options?: LatencyOptions): Promise<number>Parameters
options.pingCount: Number of pings to send (default:1). Returns the average latency when greater than 1.
const latency = await client.getLatency();
console.log("Latency:", latency, "ms");
// With multiple pings for a more accurate average
const avgLatency = await client.getLatency({ pingCount: 5 });
console.log("Average Latency:", avgLatency, "ms");On an Active Room
Measure round-trip time on an existing connection.
room.ping (callback: (ms: number) => void)room.ping((latency) => {
console.log("Latency:", latency, "ms");
});If the connection is not open, calling ping() has no effect.
Multi-Region Server Selection
Automatically connect to the server with the lowest latency from a list of endpoints.
Client.selectByLatency (endpoints: Array<string | EndpointSettings>): Promise<Client>Parameters
endpoints: Array of server endpoints (URLs or endpoint settings objects).options: Optional client options to pass to each client instance.latencyOptions.pingCount: Number of pings to send per endpoint (default:1).
import { Client } from "@colyseus/sdk";
// Select the best server from multiple regions
const client = await Client.selectByLatency([
"https://us-east.gameserver.com",
"https://eu-west.gameserver.com",
"https://asia.gameserver.com",
]);
// Now use the client with the lowest latency
const room = await client.joinOrCreate("game");The method logs the latency for each endpoint to the console for debugging purposes. If all endpoints fail to respond, an error is thrown.
HTTP Requests
The client.http utility performs HTTP requests to your server endpoint.
The client.auth.token property is sent automatically as Authorization header in all HTTP requests. See Authentication → HTTP Middleware for more details.
See Server → HTTP Routes for setting up HTTP endpoints on your server.
GET
client.http.get("/profile").then((response) => {
console.log(response.data);
});POST
client.http.post("/profile", { body: { name: "Jake Badlands" } }).then((response) => {
console.log(response.data);
});PUT
client.http.put("/profile", { body: { name: "Jake Badlands" } }).then((response) => {
console.log(response.data);
});DELETE
client.http.delete("/profile").then((response) => {
console.log(response.data);
});Room Reference
Quick reference for room properties.
| Property | Type | Description |
|---|---|---|
state | any | The synchronized room state from the server |
sessionId | string | Unique identifier for the current client connection |
roomId | string | Unique room ID (shareable for direct joins) |
name | string | Name of the room handler (e.g., "battle") |
reconnectionToken | string | Token for manual reconnection |
reconnection | ReconnectionOptions | Automatic reconnection configuration |
Next Steps
- State Sync Callbacks - Listen for state changes on the client
- Room API - Server-side room implementation
- Authentication - Secure your room connections
- Tutorials - Step-by-step game implementations