Chess — AFK timeout
The AFK system prevents games from stalling when a player goes idle. Each player has 90 seconds to make a move. The timer resets on every move — it only counts idle time, not total game time (that's the 10-minute clock).
Timeline
| At | Event | Payload | What to do |
|---|---|---|---|
| 0s | (move made) | — | AFK timer resets to 0. |
| 60s idle | chess:afk_warning | { playerId, secondsRemaining: 30 } | Show a countdown banner. If playerId === your playerId, it's urgent — you'll forfeit in 30s. |
| any move | chess:afk_warning_cleared | {} | Dismiss the banner immediately. |
| 90s idle | game:over | { winner: opponentId, reason: "afk_timeout" } | Idle player is forfeited. Opponent wins. |
chess:afk_warning — field reference
| Field | Type | Description |
|---|---|---|
playerId | string | The player who is idle. Compare to your own playerId to know if it's you or the opponent. |
secondsRemaining | number | Seconds until forfeit. Starts at 30 and counts down. The event fires once at 30s — you must count down locally. |
Disabling AFK timeout
Disable at session creation (server-side) or at join time (client-side). Client-side takes precedence.
// Option A — server-side (session creation)
body: JSON.stringify({
game: 'chess',
afkTimeoutEnabled: false,
// …
})
// Option B — client-side (matchmaking:join)
socket.emit('matchmaking:join', {
username: 'Alex',
afkTimeoutEnabled: false,
})Banner implementation
The server fires chess:afk_warning once with secondsRemaining: 30. You must run a local countdown interval to update the UI each second.
import { useState, useEffect, useRef } from 'react';
import { useSocket } from '@beta-gamer/react';
function AfkBanner({ myPlayerId }: { myPlayerId: string }) {
const socket = useSocket();
const [warning, setWarning] = useState<{ isSelf: boolean; seconds: number } | null>(null);
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
useEffect(() => {
if (!socket) return;
socket.on('chess:afk_warning', ({ playerId, secondsRemaining }) => {
setWarning({ isSelf: playerId === myPlayerId, seconds: secondsRemaining });
// Count down locally each second
intervalRef.current = setInterval(() => {
setWarning(prev => {
if (!prev || prev.seconds <= 1) {
clearInterval(intervalRef.current!);
return null;
}
return { ...prev, seconds: prev.seconds - 1 };
});
}, 1000);
});
// Clear banner when a move is made
socket.on('chess:afk_warning_cleared', () => {
clearInterval(intervalRef.current!);
setWarning(null);
});
return () => {
socket.off('chess:afk_warning');
socket.off('chess:afk_warning_cleared');
clearInterval(intervalRef.current!);
};
}, [socket, myPlayerId]);
if (!warning) return null;
return (
<div
role="alert"
className={`fixed top-4 left-1/2 -translate-x-1/2 z-50 px-6 py-3 rounded-xl font-semibold text-white shadow-lg ${
warning.isSelf ? 'bg-red-600' : 'bg-yellow-600'
}`}
>
{warning.isSelf
? `⚠️ Make a move in ${warning.seconds}s or you'll forfeit!`
: `⏳ Opponent has ${warning.seconds}s to move…`}
</div>
);
}Using the SDK? The
ChessBoard component from @beta-gamer/react, @beta-gamer/react-native, and @beta-gamer/angular includes a built-in AFK banner by default. Pass showAfkWarning={false} to disable it and use your own implementation below.⚠️ Always show the AFK banner. Players should never be forfeited without a visible countdown — it's a poor experience and will generate support requests.
Beta Gamer GaaS API — questions? support@beta-gamer.com