Client SDK

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.

client.ts
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.

The most common way to connect. Joins an existing room if available, or creates a new one.

Signature
client.joinOrCreate (roomName: string, options: any)
client.ts
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.

Signature
client.create (roomName: string, options: any)
client.ts
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.

Signature
client.join (roomName: string, options: any)
client.ts
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.

Signature
client.joinById (roomId: string, options: any)
client.ts
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

client.js
// 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.

Signature
client.consumeSeatReservation (reservation)
client.ts
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.

Signature
room.send (type, message)
client.ts
//
// 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).

Signature
room.sendBytes (type, bytes)
client.js
//
// 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.

client.ts
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.

Signature
room.state: any

On State Change

The onStateChange event fires whenever the server synchronizes state updates.

client.ts
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.

client.ts
// 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.

Signature
room.leave (consented: boolean)
client.ts
// 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).

client.ts
room.onLeave((code) => {
  console.log("client left the room");
});

Possible closing codes and their meaning:

  • 1000 - Regular socket shutdown
  • Between 1001 and 1015 - Abnormal socket shutdown
  • Between 4000 and 4999 - 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.

client.ts
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 received
  • 1006 - Abnormal closure
  • 1001 - Going away
  • 4010 - 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.

client.ts
room.onReconnect(() => {
  console.log("successfully reconnected to the room!");
});

Configuration Options

You may configure the reconnection behavior using room.reconnection.

Reconnection config options

OptionDefaultDescription
maxRetries15Maximum reconnection attempts
minDelay100Minimum delay between attempts (ms)
maxDelay5000Maximum delay between attempts (ms)
minUptime5000Minimum room uptime before reconnection is allowed (ms)
delay100Initial delay between attempts (ms)
maxEnqueuedMessages10Maximum buffered messages during reconnection
backoffexponentialDelay calculation function

Status properties (read-only)

PropertyTypeDescription
isReconnectingbooleanWhether currently reconnecting
retryCountnumberCurrent reconnection attempt count
enqueuedMessagesnumberBuffered messages

Customizing reconnection behavior:

client.ts
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 seconds

Custom backoff function:

client.ts
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.reconnectionToken from an active room connection.
  • The server needs to call .allowReconnection() for that client.
Signature
client.reconnect (reconnectionToken)
client.ts
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.

client.ts
room.onError((code, message) => {
  console.log("oops, error ocurred:");
  console.log(message);
});

Removing Listeners

Remove all event listeners from the room.

Signature
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.

Signature
client.getLatency (options?: LatencyOptions): Promise<number>

Parameters

  • options.pingCount: Number of pings to send (default: 1). Returns the average latency when greater than 1.
client.ts
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.

Signature
room.ping (callback: (ms: number) => void)
client.ts
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.

Signature
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).
client.ts
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.js
client.http.get("/profile").then((response) => {
    console.log(response.data);
});

POST

client.js
client.http.post("/profile", { body: { name: "Jake Badlands" } }).then((response) => {
    console.log(response.data);
});

PUT

client.js
client.http.put("/profile", { body: { name: "Jake Badlands" } }).then((response) => {
    console.log(response.data);
});

DELETE

client.js
client.http.delete("/profile").then((response) => {
    console.log(response.data);
});

Room Reference

Quick reference for room properties.

PropertyTypeDescription
stateanyThe synchronized room state from the server
sessionIdstringUnique identifier for the current client connection
roomIdstringUnique room ID (shareable for direct joins)
namestringName of the room handler (e.g., "battle")
reconnectionTokenstringToken for manual reconnection
reconnectionReconnectionOptionsAutomatic reconnection configuration

Next Steps