Appearance
Steam Lobbies and P2P
Multiplayer features with Steam networking.
Lobbies
requestLobbyList(distanceFilter?)
Search for available lobbies. Returns an array of lobby ID strings.
javascript
const lobbies = await steam.requestLobbyList();
// ['109775241234567890', '109775241234567891', ...]Parameters:
distanceFilter(optional) —0Close,1Default (~1500km),2Far,3Worldwide. Defaults to Worldwide so players in different regions can find each other.
Returns: string[] — array of lobby Steam IDs
Speed vs. reach
Worldwide search finds lobbies in any region but the underlying Steam matchmaking query takes longer (several seconds is normal). If you need a fast regional refresh — e.g. for an auto-refreshing browser list — pass 0 or 1 instead:
javascript
const lobbies = await steam.requestLobbyList(0); // fast, same-region onlyLobby search filters
Narrow the next requestLobbyList() call. Steam applies filters to the next search only and clears them afterwards, so set them immediately before searching.
javascript
await steam.addRequestLobbyListStringFilter('mode', 'deathmatch');
await steam.addRequestLobbyListNumericalFilter('level', 5, 2); // level >= 5
await steam.addRequestLobbyListFilterSlotsAvailable(1); // at least 1 free slot
await steam.addRequestLobbyListResultCountFilter(20); // cap results
const lobbies = await steam.requestLobbyList();Filters match against values the host published with setLobbyData().
| Method | Purpose |
|---|---|
addRequestLobbyListStringFilter(key, value, comparison?) | Match a string lobby-data value |
addRequestLobbyListNumericalFilter(key, value, comparison?) | Match a numeric lobby-data value |
addRequestLobbyListFilterSlotsAvailable(slots?) | Only lobbies with at least this many free slots |
addRequestLobbyListResultCountFilter(maxResults?) | Cap how many lobbies come back (fewer = faster) |
addRequestLobbyListDistanceFilter(distance?) | Geographic reach for this one search |
Comparison values: -2 ≤, -1 <, 0 = (default), 1 >, 2 ≥, 3 ≠
Which distance API to use
requestLobbyList(distanceFilter) is the simple way. addRequestLobbyListDistanceFilter() does the same for one search and takes precedence over the default — useful when you set several filters together. Note 0 (Close) is a valid value, not "unset".
createLobby(type, maxMembers)
Create a new lobby.
javascript
const lobbyId = await steam.createLobby(2, 4); // Public, 4 playersLobby Types:
0- Private1- Friends Only2- Public3- Invisible
joinLobby(lobbyId)
Join an existing lobby.
javascript
await steam.joinLobby(lobbyId);leaveLobby()
Leave current lobby.
javascript
await steam.leaveLobby();getLobbyData(lobbyId, key)
Get lobby metadata. Works on any lobby ID — no membership required. Use this to show lobby details (map, mode, etc.) in a browser list before joining, or to read data from your own joined lobby.
javascript
const lobbies = await steam.requestLobbyList();
const mapName = await steam.getLobbyData(lobbies[0], 'map');TIP
Steam's lobby search results carry a data snapshot, so this works immediately after requestLobbyList() without joining first.
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 IDsgetLobbyOwner()
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 memberParameters:
lobbyId- Steam lobby ID stringindex- 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 when game starts
await steam.setLobbyJoinable(true); // ReopensetLobbyType(type)
Change lobby visibility at runtime.
javascript
await steam.setLobbyType(0); // Make private
await steam.setLobbyType(2); // Make public againTypes: 0 Private, 1 FriendsOnly, 2 Public, 3 Invisible
inviteUserToLobby(steamId)
Invite a user to the lobby. Opens Steam's invite overlay for them.
javascript
await steam.inviteUserToLobby('76561198012345678');Lobby discovery
requestLobbyList() now defaults to worldwide distance filter. If your previous lobbies weren't showing up for players in different regions, updating GemShell will fix it.
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- Unreliable1- Unreliable, no delay2- Reliable3- 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
- Use reliable for important data - Score updates, game state changes
- Use unreliable for frequent updates - Position, rotation
- Validate incoming data - Never trust client data
- Handle disconnections - Clean up player state
- Rate limit sends - Don't flood the network
