NetStack

Connecting your game

Every project has its own address, shown on the project's Overview tab:

  • WebSocket: wss://yourgame.netstack.network
  • UDP: yourgame.netstack.network:7351

You can change the subdomain in the project's Settings. Games using the old address stop connecting when you do.

WebSocket

Use the client SDK in browsers and in any JavaScript runtime with a global WebSocket:

import { NetStackClient } from "./netstack-client.js";

const client = new NetStackClient({
  url: "wss://yourgame.netstack.network",
  roomId: "lobby-1",
  playerId: "alice",
});

const room = await client.connect();
console.log(room.players.length, "players in the room");

On older Node versions, pass the ws package's WebSocket as webSocketImpl. Godot projects can use the Godot addon, which handles both transports.

For engines without the SDK, any WebSocket client works. Send and receive the JSON messages described in the wire protocol.

UDP

Native engines can talk to the same rooms over UDP. Each datagram is one JSON message, using the same shapes as WebSocket.

  1. Send a join message to the UDP address, including the project API key in apiKey.
  2. Read the joined reply. It includes a session value that you should echo on later packets.
  3. Send a ping at least every 20 seconds. Sessions that stay silent for 30 seconds are dropped.
  4. Send call messages to invoke Functions and read result, event, property and propertyDelete messages as they arrive.

Keep messages small enough to fit in a single datagram (8 KB at most).

Choosing a transport

WebSocket is reliable and ordered, and is the right choice for browsers and turn-based or state-driven games. UDP avoids head-of-line blocking and suits fast native games that can tolerate loss.

Reconnecting

If a connection drops, reconnect with the same player ID. A new connection from the same IP address replaces the old, stale one immediately and the old connection receives PLAYER_REPLACED. A connection from a different address using an ID that is already in the room is refused with PLAYER_ID_TAKEN, so players cannot knock each other out.

Joining and leaving

A client joins one room per connection. Call client.leave() to leave a room and client.disconnect() to close the connection. Players are removed from the room automatically when their connection drops.