WebGame Connect
Build HTML mini games for the mssgs platform
Overview
Mini games are web pages loaded inside the mssgs client via an iframe/webview. The platform handles all session management, player tracking, and lifecycle — your game just needs to respond to webhooks and render a web UI.
How it works
A user creates a game session inside a server, players join, and each player's client loads your game's URL with session parameters. Your backend receives webhooks as players join or leave.
How It Works
Session created
A user creates a game session inside a server.
Players join
Players join the session via the mssgs client.
Game loads
Each player's client loads your game's web_url with session parameters.
Webhooks fire
Your backend receives webhooks as players join or leave.
Cleanup
When all players leave, the session is cleaned up automatically.
Game Registration
Each game is registered with the following fields:
| Field | Type | Description |
|---|---|---|
name |
string | Display name of the game |
icon_url |
string | Game icon URL |
web_url |
string | Base URL of the game web page |
max_players |
number | Maximum players allowed |
min_players |
number | Minimum players required |
webhook_join_url |
string | Called when a player joins |
webhook_leave_url |
string | Called when a player leaves |
webhook_secret |
string | Secret key for HMAC-SHA256 webhook signing |
Web URL
When a player joins a game session, the mssgs client loads your web_url with query parameters appended:
{web_url}?session={session_id}&game_user={game_user_id}
| Parameter | Type | Description |
|---|---|---|
session |
string | Game session UUID — identifies which game session this player belongs to |
game_user |
string | Unique 8-character player ID for this session |
Important
The game_user is an opaque identifier. It does not contain any personal information. Player display names are only sent to your backend via webhooks — never expose them to client-side game code unless your backend provides them.
Webhooks
Your backend receives POST requests with a JSON body from the mssgs platform as players interact with the game session. These are fire-and-forget — failures do not affect the game session.
Webhook Headers
| Header | Value |
|---|---|
Content-Type |
application/json |
User-Agent |
mssgs-webhook/1.0 |
X-Mssgs-Signature |
HMAC-SHA256 signature (only if webhook_secret is set) |
Webhook JSON Body
{
"session": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"display_name": "CoolPlayer42",
"game_user": "de875d3a",
"game_guid": "f8a1b2c3-d4e5-6789-0abc-def123456789",
"avatar_url": "https://example.com/avatar.png",
"host": true,
"callback_url": "https://mss.gs/api/v1/game-webhook/c9a1b2c3-d4e5-6789-0abc-def123456789"
}
| Field | Type | Description |
|---|---|---|
session |
string | Game session UUID |
display_name |
string | Player's display name for this session |
game_user |
string | Player's unique 8-character game user ID |
game_guid |
string | Registered game's unique identifier |
avatar_url |
string | Player's avatar URL (may be null) |
host |
boolean | Only present when player is session host (true) |
min_players |
number | Min players for session (join webhook only) |
max_players |
number | Max players for session (join webhook only) |
callback_url |
string | URL to POST channel info updates |
Join Webhook
{webhook_join_url}
Called when a player joins the session. The host field is only present when the joining player is the one who created the session. Use this to identify the game host (e.g. for starting the game, managing settings).
The min_players and max_players fields are included in join webhooks.
Leave Webhook
{webhook_leave_url}
Called when a player explicitly leaves the session. The host field is only present when the leaving player is the session host. You may want to handle host migration or end the game when the host leaves.
Disconnects
Players are not automatically removed when they disconnect (e.g. refresh, background, connection drop). They remain in the session and can rejoin. Stale sessions are cleaned up after 1 hour of inactivity.
Callback URL
Every webhook includes a callback_url — a token-authenticated URL that lets you update the game channel metadata visible to all server members.
{callback_url}
{
"description": "Round 3 — Waiting for answers...",
"thumbnail": "data:image/png;base64,iVBORw0KGgo..."
}
| Field | Type | Description |
|---|---|---|
description |
string | Short text shown under the game channel |
thumbnail |
string | Base64-encoded image (must be a data: URI) |
Both fields are optional. The payload merges into existing channel data, so you can update just the description or just the thumbnail.
Responses
| Status | Body |
|---|---|
200 OK |
{ "success": true } |
400 |
{ "error": "THUMBNAIL_MUST_BE_BASE64" } |
404 |
{ "error": "SESSION_NOT_FOUND" } |
How it works
Your backend receives a webhook, then POSTs to the callback_url. The mssgs platform broadcasts a CHANNEL_UPDATE event to all server members, updating the game channel in real time. The callback token expires when the session ends.
Example
const thumbnailBase64 = 'data:image/png;base64,' + fs.readFileSync('thumbnail.png', 'base64');
await fetch(callbackUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
description: `Round ${round} of ${totalRounds} — ${currentQuestion}`,
thumbnail: thumbnailBase64
})
});
Security
Use game_user for Player Identity
The game_user ID is the only player identifier sent to the client-side game (via the web URL). It is:
- Unique per player per session
- An opaque 8-character string
- Not reused across sessions
Player display names are only sent to your backend via webhooks, never to the client-side game. This prevents players from spoofing identities and keeps personal information out of the browser.
Validate session and game_user on your Backend
Your game's web page will send session and game_user to your backend (e.g. via WebSocket or API calls). Always validate that:
- The
sessionis a known, active session (received via a join webhook) - The
game_userwas registered via a join webhook for that session - The
game_userhas not already left (received via a leave webhook)
Webhook Signature Verification
If webhook_secret is configured, every webhook includes an X-Mssgs-Signature header containing an HMAC-SHA256 signature of the request body.
The signature format is: sha256={hex_signature}
Verification steps
- Read the raw request body (before parsing JSON)
- Compute HMAC-SHA256 using your
webhook_secret - Compare the result with the
X-Mssgs-Signatureheader
const crypto = require('crypto');
function verifyWebhook(req, webhookSecret) {
const signature = req.headers['x-mssgs-signature'];
if (!signature) return false;
const expectedSig = 'sha256=' + crypto
.createHmac('sha256', webhookSecret)
.update(req.rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSig)
);
}
import hmac
import hashlib
def verify_webhook(raw_body: bytes, signature: str, webhook_secret: str) -> bool:
expected = 'sha256=' + hmac.new(
webhook_secret.encode(),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
Constant-time comparison
Always use constant-time comparison functions (crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python) to prevent timing attacks.
Game Lifecycle
| Event | What Happens |
|---|---|
| Session created | A game channel appears in the server |
| Player joins | Join webhook fires, player list updates in channel |
| Player leaves | Leave webhook fires, player list updates |
| All players leave | Session is deleted, game channel is removed |
| 1 hour inactivity | Session is cleaned up automatically |
Architecture
Your backend maintains the game state. The mssgs platform only handles session lifecycle and player tracking — all game logic lives on your side.
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ mssgs Client │ │ mssgs Gateway │ │ Your Backend │
│ (loads iframe) │ │ (orchestrator) │ │ (game logic) │
└────────┬────────┘ └────────┬─────────┘ └────────┬────────┘
│ │ │
│ Player joins session │ │
│──────────────────────>│ │
│ │ POST webhook_join_url │
│ │────────────────────────>│
│ │ │ Store player
│ Load web_url?session=&game_user= │
│<──────────────────────│ │
│ │ │
│ Connect to your backend with session+game_user │
│────────────────────────────────────────────────>│
│ │ │ Validate
│ │ │ game_user
│ Game data (via your own WebSocket/API) │
│<────────────────────────────────────────────────│
│ │ │
Best Practices
Don't trust the client
Validate session and game_user on your backend against webhook data.
Handle disconnects gracefully
Players may leave unexpectedly. Always handle the leave webhook gracefully and consider reconnection scenarios.
Host detection
Use the host: true webhook field to identify who controls the game (e.g. for starting rounds, managing settings).
Stateless web page
Your game page should initialize purely from URL params. Don't rely on cookies or local storage for session identity.
Responsive design
Games are loaded in a webview. Ensure your UI works on both mobile and desktop.
Questions?
We're happy to help you with your game integration.
developers@mss.gs