🎮 Beta Gamer

Chess — Spectate

Any active PvP (non-bot) chess game can be watched in real time. Use the spectate lobby to browse live games, or connect directly via socket.

List live games

const res = await fetch('https://api.beta-gamer.com/v1/rooms?game=chess');
const { rooms } = await res.json();

// rooms: Array of active PvP games
// [
//   {
//     roomId:    "room_abc123",
//     players:   [{ id: "p1", username: "Alice" }, { id: "p2", username: "Bob" }],
//     moveCount: 14
//   },
//   …
// ]

Connect as spectator

Connect directly to the /chess namespace — no session token required for spectating.

import { io } from 'socket.io-client';

const socket = io('https://api.beta-gamer.com/chess', {
  path: '/socket.io',
  transports: ['websocket', 'polling'],
});

socket.on('connect', () => {
  socket.emit('game:spectate', { roomId: 'room_abc123', username: 'Spectator' });
});

// Receive the current game state immediately
socket.on('game:spectate:joined', ({ roomId, players, fen, currentTurn, moveHistory }) => {
  // render the board at fen
  // moveHistory: [{ move: { from, to, san }, playerId, timestamp }]
});

// Live updates — same events as a normal game
socket.on('game:move:made', ({ move, fen, currentTurn, moveHistory }) => {
  // update board
});

socket.on('game:over', ({ winner, reason, pgn }) => {
  // game ended — show result
});

Using the React SDK to spectate

You don't need a session token to spectate — connect the raw socket directly and use game:spectate:joined to get the initial board state. The ChessBoard component requires a BetaGamerProvider with a token, so for spectating you manage board state manually via useSocket() and render your own board, or use the raw socket approach below.

import { useEffect, useRef, useState } from 'react';
import { io } from 'socket.io-client';

export default function SpectateRoom({ roomId }: { roomId: string }) {
  const [fen, setFen] = useState('');
  const [players, setPlayers] = useState<any[]>([]);
  const [moveHistory, setMoveHistory] = useState<any[]>([]);
  const socketRef = useRef<any>(null);

  useEffect(() => {
    const socket = io(window.location.origin + '/chess', {
      path: '/api/socket/io',
      transports: ['websocket', 'polling'],
    });
    socketRef.current = socket;

    socket.on('connect', () => {
      socket.emit('game:spectate', { roomId, username: 'Spectator' });
    });

    socket.on('game:spectate:joined', ({ players: p, fen: f, moveHistory: h }) => {
      setPlayers(p);
      setFen(f);
      setMoveHistory(h);
    });

    socket.on('game:move:made', ({ fen: f, moveHistory: h }) => {
      setFen(f);
      setMoveHistory(h);
    });

    socket.on('game:over', ({ winner, reason }) => {
      console.log('Game ended:', reason, winner);
    });

    return () => { socket.disconnect(); };
  }, [roomId]);

  // Render your own read-only board using fen, players, moveHistory
  return null;
}

Event reference

EventDirectionPayload
game:spectate→ server{ roomId, username }
game:spectate:joined← server{ roomId, players, fen, currentTurn, moveHistory }
game:move:made← server{ move: { from, to, san, piece }, fen, currentTurn, moveHistory }
game:over← server{ winner?, reason, pgn }
💡 Only PvP games (no bots) are listed. Bot games are excluded from the spectate lobby.
Beta Gamer GaaS API — questions? support@beta-gamer.com