Case Study - Real-Time Multiplayer Card Game with Socket.io

A browser-based multiplayer card game supporting 2-5 players with real-time synchronisation, reconnection handling, and spectator mode.

Client
The Web People
Year
Service
Web Development, Custom Applications
Real-Time Multiplayer Card Game interface

Overview

This project demonstrates the implementation of a fully-functional, real-time multiplayer card game designed for 2-5 players competing across different devices. Players race to empty their hand first, with the last remaining player declared the loser.

The application showcases modern real-time web development patterns using Socket.io for WebSocket communication, with a focus on seamless multiplayer experiences, robust error handling, and server-authoritative game state.

The Challenge

Building a real-time multiplayer game presents several technical challenges:

  • State Synchronisation — All players must see the same game state, updated instantly when anyone plays
  • Cheating Prevention — Clients can't be trusted; the server must validate every action
  • Disconnection Handling — Players drop connections; the game should handle this gracefully
  • Security — Rate limiting and input validation to prevent abuse
  • Scalability — Architecture that could support persistent storage in the future

Key Features

Room-Based Multiplayer

Players create or join game rooms using simple 4-character codes. QR code generation makes sharing room links effortless—just scan to join on mobile.

Real-Time Gameplay

Socket.io enables instant updates across all connected clients. When a player makes a move, everyone sees the result immediately—no page refreshes, no polling delays.

Spectator Mode

A dedicated table view displays the game for spectators on larger screens like tablets or TVs. This view shows all public information without revealing any player's hand.

Seamless Reconnection

JWT-based sessions allow players to reconnect after network interruptions. Close the browser, lose wifi, switch networks—when you come back, you're right where you left off.

Turn-Based Validation

The server maintains authoritative game state and validates every play attempt. Trying to play out of turn, play invalid cards, or manipulate game state simply doesn't work.

Technical Architecture

Server-Side

The custom Next.js server runs with Socket.io attached, handling all real-time communication:

Room Manager

A synchronous facade over a repository pattern manages room lifecycle—creation, joining, leaving, and automatic cleanup of abandoned rooms after 2 hours.

Socket Handler

12+ event handlers process room management and game actions. Rate limiting prevents abuse (100 events/minute per socket, 10 join attempts/minute per IP), while comprehensive input validation sanitises all user input.

Personalised Broadcasting

Each player receives a customised view of game state. Opponents' hands appear as card counts rather than actual cards—the server never sends information a player shouldn't see.

Game Logic

All game logic uses pure functions with immutable state, enabling deterministic gameplay and comprehensive testing:

Card Validation

The rules engine handles complex card interactions: reset cards that allow any play, reverse cards that require lower values, burn cards that clear the pile, and automatic burns from four-of-a-kind plays.

State Machine

The game progresses through defined phases: waiting, swap (pre-game card exchange), playing, game ending (brief delay for visual feedback), and finished. Each phase has specific allowed actions.

Client-Side

React Context provides app-wide socket connection access. The single socket instance persists for the entire session, with automatic reconnection attempts and session restoration.

Security

  • Rate Limiting — Prevents spam and abuse
  • Input Validation — All Socket.io inputs validated before processing
  • Authorization — Host-only actions verified server-side
  • Turn Validation — Prevents out-of-turn plays
  • HTTP-Only JWT Cookies — Secure session management

Testing & Quality

The codebase includes comprehensive test coverage using Vitest:

  • Game state transition tests
  • Card validation and special card effect tests
  • Input sanitisation tests
  • Integration tests for game flows

All tests can run with UI visualisation for debugging, and coverage reports identify any gaps.

Architecture for Scale

The repository pattern abstracts data storage, currently using in-memory JavaScript Maps. This design allows straightforward migration to Redis or PostgreSQL for persistent game state without changing any game logic.

The production roadmap includes turn timeouts for inactive players, database persistence for game history, and additional UX polish with animations and accessibility improvements.

What we did

More case studies

A Lightweight iOS Speedometer with Premium Features

A native iOS speedometer app built with SwiftUI featuring real-time GPS tracking, in-app purchases, and accessibility-first design.

Read more

Scaling Course Enrolment Through Strategic SEO and Digital Marketing

How we helped a leading UK training provider increase course bookings by over 300% through 10 years of SEO optimisation and digital marketing strategy.

Read more

Tell us about your project