Room Visibility & Access
Which rooms a player can discover, and which they can actually enter, are two different questions. Three flags answer them.
Matchmaking Properties
Three boolean flags control who can find and join a room: locked, private, and unlisted. They sound similar but behave differently on each join path:
join() / joinOrCreate() | joinById() | Lobby / listing queries | |
|---|---|---|---|
locked | skipped | rejected (room "…" is locked) | listed (as locked) |
private | skipped | allowed | hidden |
unlisted | matched | allowed | hidden |
locked: no new clients can join, on any path. Set automatically when the room fills up (maxClientsreached, releases itself when a seat frees), or explicitly vialock(). Reconnections still work: a reconnecting client returns to the seat it already owned.private: invite-only. Never matched byjoin()/joinOrCreate()and never shown in listings, but anyone holding the room ID can enter throughjoinById(). Use it for invite links and party codes. Set viasetPrivate()orsetMatchmaking({ private: true }).unlisted: hidden, but still matchmade. The room doesn’t show up in lobby/listing queries, yetjoin()/joinOrCreate()keep filling it normally. Use it to keep rooms out of your room browser without pulling them from matchmaking. Set viasetMatchmaking({ unlisted: true }).
Looking for passwords? There is no built-in password concept: private does not imply a password. To gate a room behind a password, combine filterBy(), unlisted, and an onAuth() check: see Password Protect Room.
setMatchmaking(updates)
Updates multiple matchmaking/listing properties at once, with a single persist operation. This method is the recommended way to update room listing properties.
metadata(optional): room metadata (replaces the existing value)private(optional): whether the room should be privatelocked(optional): whether the room should be lockedmaxClients(optional): maximum number of clients allowedunlisted(optional): whether the room should be hidden from listing queries
// Update multiple properties at once
await this.setMatchmaking({
metadata: { difficulty: "hard", rating: 1500 },
private: true,
locked: true,
maxClients: 10
});metadata is replaced, never merged. To merge, spread the current value yourself:
setMatchmaking({ metadata: { ...this.metadata, round: 2 } }).
You can also set individual properties:
setPrivate(bool?): toggleprivate(defaults totrue)setMetadata(meta): replacemetadatalock()/unlock(): togglelockedthis.maxClients = N: forwards tosetMatchmaking({ maxClients: N })
Lock Room
Locking removes the room from matchmaking: join()/joinOrCreate() skip it, and joinById() rejects with a room "<roomId>" is locked error. No new clients can join until it’s unlocked.
this.lock();The room also locks automatically when it reaches maxClients. The two differ in how they release: an automatic lock releases itself as soon as a seat frees up, while an explicit lock() is sticky. The room stays locked until you call unlock().
Unlock Room
Returns the room to the pool of available rooms. New clients can join again, as long as maxClients hasn’t been reached.
this.unlock();