Skip to content

Steam Lobbies and P2P

Multiplayer features with Steam networking.

Lobbies

requestLobbyList()

Search for available lobbies. Returns an array of lobby ID strings.

javascript
const lobbies = await steam.requestLobbyList();
// ['109775241234567890', '109775241234567891', ...]

Returns: string[] — array of lobby Steam IDs

createLobby(type, maxMembers)

Create a new lobby.

javascript
const lobbyId = await steam.createLobby(2, 4); // Public, 4 players

Lobby Types:

  • 0 - Private
  • 1 - Friends Only
  • 2 - Public
  • 3 - Invisible

joinLobby(lobbyId)

Join an existing lobby.

javascript
await steam.joinLobby(lobbyId);

leaveLobby()

Leave current lobby.

javascript
await steam.leaveLobby();

getLobbyData(key)

Get lobby metadata from current lobby.

javascript
const mapName = await steam.getLobbyData('map');

setLobbyData(key, value)

Set lobby metadata (owner only).

javascript
await steam.setLobbyData('map', 'forest');
await steam.setLobbyData('mode', 'deathmatch');

getLobbyMembers()

Get list of members in current lobby.

javascript
const members = await steam.getLobbyMembers();
// Array of Steam IDs

getLobbyOwner()

Get the lobby owner's Steam ID (uses current lobby).

javascript
const owner = await steam.getLobbyOwner();
// '76561198012345678'

Returns: Steam ID string, or empty string if no current lobby.

getLobbyMemberCount(lobbyId)

Get the number of members currently in a lobby.

javascript
const count = await steam.getLobbyMemberCount(lobbyId);

Parameters:

  • lobbyId - Steam lobby ID string

Returns: number — member count (0 if lobby not found or not yet joined)

getLobbyMemberByIndex(lobbyId, index)

Get the Steam ID of a specific lobby member by index.

javascript
const memberId = await steam.getLobbyMemberByIndex(lobbyId, 0); // first member

Parameters:

  • lobbyId - Steam lobby ID string
  • index - Zero-based member index

Returns: Steam ID string, or empty string if index out of range.

getLobbyMemberLimit()

Get maximum number of members allowed.

javascript
const max = await steam.getLobbyMemberLimit();

setLobbyJoinable(joinable)

Set whether the lobby can be joined.

javascript
await steam.setLobbyJoinable(false); // Lock lobby

inviteUserToLobby(steamId)

Invite a user to the lobby.

javascript
await steam.inviteUserToLobby('76561198012345678');

P2P Networking

sendP2PPacket(steamId, data, type)

Send data to another player.

javascript
const packet = JSON.stringify({ type: 'move', x: 100, y: 200 });
await steam.sendP2PPacket(targetSteamId, packet, 2);

Channel Types:

  • 0 - Unreliable
  • 1 - Unreliable, no delay
  • 2 - Reliable
  • 3 - Reliable, buffered

readP2PPacket()

Read incoming packet.

javascript
const packet = await steam.readP2PPacket();
if (packet) {
  const data = JSON.parse(packet.data);
  const sender = packet.steamId;
}

acceptP2PSessionWithUser(steamId)

Accept incoming connection.

javascript
await steam.acceptP2PSessionWithUser(steamId);

closeP2PSessionWithUser(steamId)

Close connection.

javascript
await steam.closeP2PSessionWithUser(steamId);

Examples

Host Game

javascript
async function hostGame(maxPlayers = 4) {
  // 0 = Private, 1 = FriendsOnly, 2 = Public, 3 = Invisible
  const lobbyId = await steam.createLobby(2, maxPlayers);
  
  if (lobbyId) {
    console.log('Lobby created:', lobbyId);
    const members = await steam.getLobbyMembers();
    console.log('Members:', members);
  }
  
  return lobbyId ?? null;
}

Browse Lobbies

javascript
async function findLobbies() {
  const lobbies = await steam.requestLobbyList();
  // lobbies is an array of lobby ID strings
  
  const details = [];
  for (const lobbyId of lobbies) {
    const memberCount = await steam.getLobbyMemberCount(lobbyId);
    details.push({ lobbyId, memberCount });
  }
  
  return details;
}

Full Lobby Flow

javascript
async function lobbyDemo() {
  // Create a public lobby for up to 4 players
  const lobbyId = await steam.createLobby(2, 4);
  if (!lobbyId) return;

  // Check who joined
  const members = await steam.getLobbyMembers();
  const owner = await steam.getLobbyOwner();
  console.log(`Owner: ${owner}, Members: ${members.join(', ')}`);

  // Get count using explicit ID (useful when browsing lobbies)
  const count = await steam.getLobbyMemberCount(lobbyId);
  const first = await steam.getLobbyMemberByIndex(lobbyId, 0);

  // Leave when done
  steam.leaveLobby();
}

Network Loop

javascript
function networkUpdate() {
  // Process incoming packets
  let packet;
  while ((packet = steam.readP2PPacket())) {
    handlePacket(packet.steamId, JSON.parse(packet.data));
  }
}

function handlePacket(sender, data) {
  switch (data.type) {
    case 'move':
      updatePlayerPosition(sender, data.x, data.y);
      break;
    case 'chat':
      addChatMessage(sender, data.message);
      break;
    case 'action':
      handlePlayerAction(sender, data.action);
      break;
  }
}

// Send position update
function sendPosition(x, y) {
  const packet = JSON.stringify({ type: 'move', x, y });
  for (const playerId of connectedPlayers) {
    steam.sendP2PPacket(playerId, packet, 1); // Unreliable, no delay
  }
}

Reliable Messages

javascript
async function sendReliableMessage(steamId, data) {
  const packet = JSON.stringify(data);
  await steam.sendP2PPacket(steamId, packet, 2); // Reliable
}

// Use for important events
async function onPlayerScored(steamId, points) {
  await sendReliableMessage(steamId, {
    type: 'score',
    points,
    timestamp: Date.now()
  });
}

Best Practices

  1. Use reliable for important data - Score updates, game state changes
  2. Use unreliable for frequent updates - Position, rotation
  3. Validate incoming data - Never trust client data
  4. Handle disconnections - Clean up player state
  5. Rate limit sends - Don't flood the network