Skip to main content
Developer Guide

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

1

Session created

A user creates a game session inside a server.

2

Players join

Players join the session via the mssgs client.

3

Game loads

Each player's client loads your game's web_url with session parameters.

4

Webhooks fire

Your backend receives webhooks as players join or leave.

5

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:

URL Format
{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

Request 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

POST {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

POST {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.

POST {callback_url}
Request Body
{
  "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

Node.js
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:

  1. The session is a known, active session (received via a join webhook)
  2. The game_user was registered via a join webhook for that session
  3. The game_user has 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

  1. Read the raw request body (before parsing JSON)
  2. Compute HMAC-SHA256 using your webhook_secret
  3. Compare the result with the X-Mssgs-Signature header
Node.js
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)
  );
}
Python
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.

Architecture Overview
┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  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