Quick match
Call matchRoom to put players into a shared room through a queue. The default queue matches two players. Use room codes for invitations and private games.
Default room codes are short so they can be read aloud, which makes them fine for casual, public
invites and easy to guess. For a private game, create the room with privateCode: true (a
10-character code) and join from the link with mustExist: true, or bind the room to a JWT, which is the strongest option. See private links.
// main.ts
import { matchRoom } from '@irtio/client';
import { schema } from './irtio/schema';
const room = await matchRoom(schema); // waits for an opponent, then joins Quick match requires a deployed project and the hosted control API (https://irt.io by default). irtio dev does not serve matchmaking: pointing controlUrl at it returns E_HTTP_404, or E_MATCH_UNREACHABLE if no server is listening.
To test a deployed queue:
npx irtio simulate --bots 4 --queue 1v1 --control https://irt.io --queue requires --control. In Node, also pass the deployed room endpoint as url to matchRoom; see Node matchmaking.
What happens
- Each client posts to the queue and the request stays open while they wait.
- When enough players are waiting, irtio mints one fresh room code and answers everyone in the party with it at the same moment.
- Each client joins that code with the ordinary join path.
Step 3 is the important one. There is no special “matched room”: the room is created by whoever joins first, exactly as it would be if a friend had sent the code in a chat message. Capacity, hibernation and everything else behave identically. Your room code cannot tell that a matchmaker was involved, and does not need to.
Waiting, and not matching
The call takes as long as the queue takes. If nobody else shows up before the deadline it throws E_NO_MATCH with how many players were waiting, and you decide what happens next:
// main.ts
try {
const room = await matchRoom(schema, { timeoutMs: 20_000 });
} catch (err) {
if (err.code === 'E_NO_MATCH') {
// Nobody around. Offer a room code, a bot, or a "try again" button.
}
} It will not quietly put a player alone in a room and call that a match. A player sitting in an empty arena wondering where their opponent is has been lied to.
To render your own waiting state, findMatch is the queue call on its own. It resolves with the room
code and leaves the joining to you. GET /match/status?project=<id> reads how many are waiting
without queueing anyone, which is what “2 of 4 waiting” is made of.
Queues
Every project has one queue without configuring anything: default, a party of two. That is why matchRoom(schema) works against a brand new project.
Named queues are per-project configuration. Declare them in irtio.json, next to the room code
that consumes them, and every deploy keeps the project in sync:
"queues": { "1v1": { "size": 2 }, "ffa": { "size": 8 } } The API works too, for a dashboard or a change mid-event; a declared queues key wins again on
the next deploy. See irtio.json.
curl -X PATCH https://irt.io/v1/projects/<id>
-H 'content-type: application/json'
-d '{"name":"my game","queues":{"1v1":{"size":2},"ffa":{"size":8}}}' // main.ts
const room = await matchRoom(schema, { queue: 'ffa' }); Once a project declares any queue, default stops being implicit. A project that wants one says so.
Asking for a queue that is not configured is an error rather than a queue of one that never fills.
Identity, and why you want it
// main.ts
const room = await matchRoom(schema, { queue: '1v1', identity: true }); With an identity, the queue holds one ticket per player: queueing twice retires the earlier request instead of matching a player against themselves. Without one, the queue cannot tell two tabs apart from two people, and all that stands between a queue and one bored person filling it is the per-address rate limit.
Quick match works without identities so you can try it in an afternoon. Ship it with them.
More ways to match
See matchmaking recipes for skill queues, teams, parties, backfill, and public games.
Limits
POST /match is a public endpoint, so it is rate limited per address and per project. A ticket dies
with its connection: close the tab and the entry leaves the queue immediately, so a queue cannot fill
with players who will never arrive. The numbers are on the limits page.
Related
- Player identity for the ids a ranked queue needs.
- Presence and lifecycle for what happens once players land in the room.