Skip to content
BingWow

Building a Multiplayer Bingo Room with Next.js, Ably, and Supabase

BingWow looks like a simple bingo game, but the multiplayer flow has a few constraints that make the architecture interesting: players can start without an account, single-player games should feel instant, multiplayer rooms need independent boards, and the same URL has to survive phone browsers, laptops, and video-call chats.

This is the architecture we use in production: Next.js App Router for routes and API endpoints, React for the game UI, Supabase Postgres for room/player state, and Ably for low-latency events.

The Product Constraint

A visitor can open a public card, get a private fork, and start playing immediately. In that single-player mode, taps should never wait on the network. The player is alone, so local state is enough.

When someone shares the invite link and a second player joins, the game changes shape. Every player now needs their own independent board, taps must be server-authoritative, and round transitions need to be consistent for the room.

The State Split

  • Single-player: claims live in the browser. Tapping a cell is local and immediate.
  • Multiplayer: each tap hits a Next.js API route, writes authoritative state to Supabase, and then clients receive one realtime event.
  • Rounds: round numbers are stored server-side and included in events so clients can ignore stale messages.

The important rule is that Ably delivers events; it does not become the database. If a browser reconnects or refreshes, the durable source is the room and player rows in Supabase.

Why Each Player Gets a Different Board

Bingo feels broken when everyone has the same path to victory. BingWow generates an independent randomized board for every player from the same clue set. Everyone is watching for the same theme, but no two boards are laid out the same way.

That matters for fairness and for engagement. A player wins by completing their own row, not by racing through a shared global checklist.

The Tap Path

In multiplayer, a tap follows one narrow path:

  1. The client optimistically updates the tapped cell.
  2. The browser sends one request to the tap API route with room, player, round, and cell identity.
  3. The server validates the player, updates the board state in Supabase, and returns the accepted state.
  4. The client publishes or receives the room event so other browsers reconcile to the same state.

Keeping claim and unclaim as one unified tap operation matters. Two separate operations sound clean at first, but they create more race surfaces than the game needs.

Round Numbers Prevent Old Echoes

Realtime systems love stale messages. A browser can reconnect, a channel can replay, or a user can change rounds while another event is in flight. BingWow includes the room round number in every game event and ignores events that belong to a previous round.

That one field prevents a surprising class of bugs: old claims appearing after a reset, stale bingo overlays, and late-arriving round transitions.

Serverless Reality

Vercel serverless functions are good for request/response work, but long-running fire-and-forget behavior is a trap. When a response is already sent, the platform can freeze the function before a background publish finishes. BingWow avoids depending on that pattern for user-visible realtime events.

The broader lesson: make the database write the durable truth, return a clear HTTP response, and let browser-connected clients handle realtime fanout where appropriate.

What We Would Keep If Rebuilding

  • Single-player taps stay local until another player joins.
  • The server owns multiplayer tap acceptance.
  • Realtime events carry round numbers and are treated as hints to reconcile, not permanent truth.
  • Every player gets their own board from the same clue set.
  • Room URLs include enough identity to rejoin without forcing signup.

If you just want to play, start with the card library or create a custom card. If you are building realtime React apps, the pattern is the transferable part: local where solo, server-authoritative where shared, and realtime events as delivery rather than truth.

Frequently Asked Questions

What stack does BingWow use for multiplayer bingo?
BingWow uses Next.js App Router, React, Supabase Postgres, and Ably WebSockets. Single-player taps stay local, while multiplayer taps go through a server-authoritative API route and then sync through Ably.
Why not use WebSocket presence as the source of truth?
Presence can include ghost members after refreshes and reconnects. BingWow treats the database-backed room/player state as authoritative and uses realtime events as delivery, not truth.
How does single-player become multiplayer?
A visitor starts from a private fork and taps locally. When another player joins, the host receives a player-joined event, clears solo-only marks, and navigates into the multiplayer room where the server owns tap state.

Ready to try it?

Create your own bingo card in seconds — free, no signup required.

Create a Card