Quick start — React Native
End-to-end: from an API key to a live match in your Expo or bare React Native app — no SDK required.
@beta-gamer/react-native exists on npm but predates the current hosted-matchmaking architecture and isn't updated for it — installing it today won't give you a working integration. It's being rebuilt separately and will come back once it matches what's live. This guide — plain socket.io-client plus a small hook — is the real, working path right now, not a stopgap.Get your API key
Same as the web flow — a bg_live_… key and a bg_test_… key. Use the test key while developing.
Install the one real dependency
npm install socket.io-clientio(url, { auth: { token }, autoConnect: false, transports: ['websocket'] });Create a session (your backend)
Call POST /v1/sessions from your server and return the sessionToken to the app. Never call this from the device — it needs your secret API key.
const res = await fetch('https://api.beta-gamer.com/v1/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer bg_live_xxxx',
'Content-Type': 'application/json',
},
body: JSON.stringify({
game: 'checkers',
matchType: 'matchmaking',
players: [{ id: user.id, displayName: user.name }],
}),
});
const { sessionToken, sessionId } = await res.json();Fetch the token in your app
const startGame = async () => {
const res = await fetch('https://your-api.com/game/start', {
method: 'POST',
headers: { 'Authorization': `Bearer ${userAuthToken}` },
});
const { sessionToken, sessionId } = await res.json();
navigation.navigate('Game', { sessionToken, sessionId });
};Write a small connection hook
Same hook as the web guide, with transports: ['websocket'] added:
// useBetaGamerSocket.ts
import { useEffect, useRef, useState } from 'react';
import { io, Socket } from 'socket.io-client';
export function useBetaGamerSocket(game: string, sessionToken: string | null) {
const socketRef = useRef<Socket | null>(null);
const [connected, setConnected] = useState(false);
useEffect(() => {
if (!sessionToken) return;
const socket = io(`https://api.beta-gamer.com/${game}`, {
auth: { token: sessionToken },
autoConnect: false,
transports: ['websocket'],
});
socketRef.current = socket;
socket.on('connect', () => setConnected(true));
socket.on('disconnect', () => setConnected(false));
socket.connect();
return () => {
socket.disconnect();
socketRef.current = null;
};
}, [game, sessionToken]);
return { socket: socketRef.current, connected };
}Join matchmaking, render from state
There's no ChessBoard-style pre-built component without the SDK — you own rendering. That's more upfront work, and also means your board looks exactly like your app, not like a generic default.
export default function GameScreen({ route }) {
const { sessionToken } = route.params;
const { socket, connected } = useBetaGamerSocket('checkers', sessionToken);
const [board, setBoard] = useState(null);
const [status, setStatus] = useState('Connecting…');
useEffect(() => {
if (!socket || !connected) return;
socket.emit('matchmaking:join', { playerId: myId, username: myName });
socket.on('game:started', (data) => {
setBoard(data.board);
setStatus(`Game started — you're ${data.color}`);
});
socket.on('game:move:made', (data) => setBoard(data.board));
socket.on('game:over', ({ winner }) => {
setStatus(winner === myId ? 'You won!' : winner ? 'You lost' : 'Draw');
});
return () => { socket.off('game:started'); socket.off('game:move:made'); socket.off('game:over'); };
}, [socket, connected]);
if (!board) return <ActivityIndicator />;
return <YourOwnBoardComponent board={board} onCellPress={(from, to) =>
socket.emit('game:move', { roomId, playerId: myId, move: { from, to } })
} />;
}Validate the token on mount
Tokens are single-use. Validate before rendering the game screen so navigating back to a finished match shows the result, not a socket trying to rejoin something that's already over.
useEffect(() => {
fetch(`https://api.beta-gamer.com/v1/sessions/validate?token=${sessionToken}`)
.then(r => r.json())
.then(d => setStatus(d.status === 'ended' ? 'ended' : 'ok'))
.catch(() => setStatus('ok'));
}, [sessionToken]);A note on mobile lifecycle
| Concern | Note |
|---|---|
| App backgrounded mid-game | The socket disconnects like any background app. Reconnect on foreground using the same sessionToken and the per-game reconnect event — see each game’s own page. |
| Metro / dev server restarts | Behaves like any other socket disconnect from the server’s point of view — no special handling needed beyond normal reconnection. |