LiaDevelopers

Guides

A two player room. Create it on your server, invite a friend into it with Lia's friend picker or a link, and land both players in the same room.

The idea: a room has an id, and the id goes in the invite's startParam. Whoever opens the invite opens your app with that startParam, and your page joins them to the room. Lia's own Lia XO works this way.

#1. Create a room on your server

server.js
app.post("/api/rooms", async (req, res) => {
  const playerId = await playerFrom(req.body.session); // see Verify on your server
  if (!playerId) return res.status(401).end();
  const room = "room-" + crypto.randomUUID().replace(/-/g, "").slice(0, 10);
  await db.createRoom(room, { host: playerId, players: [playerId] });
  res.json({ room });
});

app.post("/api/rooms/join", async (req, res) => {
  const playerId = await playerFrom(req.body.session);
  if (!playerId) return res.status(401).end();
  const room = await db.room(req.body.room);
  if (!room) return res.status(404).json({ error: "no_room" });
  if (room.players.length >= 2 && !room.players.includes(playerId)) return res.status(409).json({ error: "full" });
  await db.addPlayer(req.body.room, playerId);
  res.json({ room: req.body.room });
});

Room ids must fit a startParam: 1 to 64 of letters, digits, _ and -.

#2. Invite a friend

game.js
async function playWithAFriend() {
  const { room } = await api("/api/rooms", {});
  showWaiting(room);
  const { invited } = await Lia.inviteFriend({ startParam: room });
  if (!invited) Lia.toast("Share the link to invite someone");
}

// Or a link to send anywhere: opens your app in Lia, or the App Store without it.
async function shareRoom(room) {
  await Lia.share("Play with me: " + Lia.inviteLink(room));
}

Each friend picked gets a card in their Lia chat. Lia only lets people invite their friends, and only friends who can open your app (while it's in test, only your testers).

#3. Land in the room

Read the startParam when your app opens, and listen for one arriving while it's open (the person taps a second invite):

JavaScript
function route(startParam) {
  if (startParam && startParam.startsWith("room-")) joinRoom(startParam);
}

Lia.init().then(function () {
  route(Lia.startParam);
  Lia.ready();
});
Lia.on("startParam", function (data) { route(data.startParam); });

async function joinRoom(room) {
  try {
    await api("/api/rooms/join", { room });
    openTable(room);
  } catch (error) {
    Lia.toast(error.message === "full" ? "That game is full" : "That game has ended");
  }
}

A startParam is only a hint: anyone can make a link with any startParam, so your server decides whether the room exists and the player may join.

#4. Play live

Connect both players to your server (a WebSocket is usual), and verify each player's session before joining them to the room. While a game is on:

JavaScript
Lia.enableClosingConfirmation(); // "Leave the game?" if they close
Lia.disableVerticalSwipes();     // a swipe down won't close the sheet mid move
Lia.onPause(function () { socket.send(JSON.stringify({ type: "away" })); });
Lia.onResume(function () { socket.send(JSON.stringify({ type: "back" })); });

#5. Your turn, by notification

When it's someone's move and they've left your app, a notification with the room as its startParam brings them straight back:

JSON
{ "playerId": "p_3f9c0a6d1b2e4f5a6b7c", "text": "@kofi played. Your move.", "startParam": "room-a81c2e09f4" }

#Public tables

Invites are for friends. To let anyone on Lia join, also list the room in the lobby while it waits:

server.js
// When the room is made: list it (as the host, with one seat taken).
await lia("POST", "/lobby/tables", { tableId: room, hostPlayerId: playerId, seats: 2, taken: 1, title: "Quick game" });

// When someone joins from the lobby: seat them through Lia first (it refuses blocked players and full tables).
app.post("/api/rooms/sit", async (req, res) => {
  const playerId = await playerFrom(req.body.session);
  if (!playerId) return res.status(401).end();
  try {
    const { full } = await lia("POST", `/lobby/tables/${encodeURIComponent(req.body.room)}/sit`, { playerId });
    await db.addPlayer(req.body.room, playerId);
    if (full) startGame(req.body.room);
    res.json({ room: req.body.room });
  } catch (error) {
    res.status(409).json({ error: error.data?.error ?? "failed" }); // full, not_found, own_table
  }
});

// When the game starts or the room closes: take it out (safe to repeat).
await lia("DELETE", `/lobby/tables/${encodeURIComponent(room)}`);

In your page, show the open tables, and seat people who chose your table in Lia's own lobby (they arrive with the startParam lobby-<table id>):

JavaScript
const { tables } = await Lia.lobby.tables();
renderTables(tables, (table) => api("/api/rooms/sit", { room: table.id }));

function route(startParam) {
  if (startParam?.startsWith("lobby-")) return api("/api/rooms/sit", { room: startParam.slice(6) }).then(openTable);
  if (startParam?.startsWith("room-")) return joinRoom(startParam);
}

Strangers can't chat through Lia, blocks are respected, and players can report each other.

#Limits to know

  • One person can invite 20 friends into your app a day, so invites stay something people welcome in their chats.
  • A host can have 3 open public tables in your app at a time, and a listing lasts at most an hour.
  • Lia.inviteFriend() answers { invited }, never who was invited: your server learns who joined when they join.

Type to search every page, method and endpoint.