bootstrap.gx.ag

Peer-to-peer connection bootstrapping over WebSocket.

This server helps two peers find each other and exchange signalling data. Connect over WebSocket, discover a peer via short share codes, and relay messages to complete a handshake. Connections can stay open as long as needed — for example, to host a game and accept incoming peers — but throughput is rate-limited to signalling use.

There are two ways to use the server:

Ephemeral (share codes) — Connect and request a share code (4–6 letters), then give it to peers out-of-band. They look up the code to find your ID and start exchanging messages. The code is released when you disconnect. Good for hosting a session that others join by code.

Persistent (registered identity) — Connect and register a token. Store the token and reconnect with it later to keep the same UUID across sessions. Peers who already know your ID can message you whenever you're connected. Good for a server with a permanent ID.

Connect

Open a WebSocket connection to the /v1 endpoint:

ws://HOST/v1              # new identity (assigned a random UUID)
ws://HOST/v1?token=TOKEN  # resume a registered identity

On success the server immediately sends your client ID:

 { "type": "id", "id": "550e8400-e29b-41d4-a716-446655440000" }

All subsequent messages are JSON text frames. Every request you send can include an optional "mid" field (any JSON value). The server echoes it back on the corresponding response so you can match request/response pairs.

Messages

register

Generate a token that persists your identity across connections. Store the token and pass it as the ?token= query parameter on reconnect to keep the same UUID.

 { "type": "register" }
 { "type": "register", "token": "BASE64_TOKEN" }

share

Acquire a short alphanumeric share code that other peers can look up to find your ID. The code is assigned once per connection — calling share again returns the same code. The code is released when you disconnect.

 { "type": "share" }
 { "type": "share", "code": "BFKM" }

Codes are 4–6 uppercase consonants (no vowels), all distinct. Shorter codes are preferred when available.

lookup

Resolve a share code to the peer's UUID.

 { "type": "lookup", "code": "BFKM" }
 { "type": "lookup", "id": "550e8400-e29b-41d4-a716-446655440000" }

message

Send a text payload to another connected peer by UUID. The server relays the message and responds with an acknowledgement.

# sender
 { "type": "message", "recipient": "RECIPIENT_UUID", "text": "..." }
 { "type": "ack" }

# recipient receives
 { "type": "message", "sender": "SENDER_UUID", "text": "..." }

error

Returned when a request fails. Includes the mid from the original request if one was provided.

 { "type": "error", "message": "Code not found: ZZZZ" }

Example Flows

Ephemeral: share code session

A host opens a session and gives out a share code. Players join by code.

# Host connects
Host  server    { "type": "id", "id": "HOST_UUID" }

# Host requests a share code
Host  server    { "type": "share" }
Host  server    { "type": "share", "code": "BFKM" }

# Host displays "BFKM" in the lobby UI

# Player connects and looks up the code
Player  server  { "type": "id", "id": "PLAYER_UUID" }
Player  server  { "type": "lookup", "code": "BFKM" }
Player  server  { "type": "lookup", "id": "HOST_UUID" }

# Player sends signalling data to Host
Player  server  { "type": "message", "recipient": "HOST_UUID", "text": "{\"sdp\":\"...\"}" }
Host    server  { "type": "message", "sender": "PLAYER_UUID", "text": "{\"sdp\":\"...\"}" }

# They exchange messages until the P2P handshake completes
# Host stays connected to accept more players

Persistent: registered identity

A server registers once, stores its token, and reconnects with the same UUID across restarts. Clients who know the UUID can reach it any time it's connected.

# Server connects for the first time
Server  server  { "type": "id", "id": "SERVER_UUID" }

# Server registers to get a token
Server  server  { "type": "register" }
Server  server  { "type": "register", "token": "BASE64_TOKEN" }

# Server stores TOKEN and SERVER_UUID (e.g. publish UUID in app config)

# ... later, server reconnects with the same identity
Server  ws://HOST/v1?token=BASE64_TOKEN
Server  server  { "type": "id", "id": "SERVER_UUID" }  # same UUID as before

# Client already knows SERVER_UUID, connects and messages directly
Client  server  { "type": "id", "id": "CLIENT_UUID" }
Client  server  { "type": "message", "recipient": "SERVER_UUID", "text": "{\"sdp\":\"...\"}" }
Server  server  { "type": "message", "sender": "CLIENT_UUID", "text": "{\"sdp\":\"...\"}" }

# They exchange messages until the P2P handshake completes

Rate Limits

Throughput is rate-limited to signalling use.

ScopeLimit
WebSocket connections per IPburst 3, ~6/min sustained
Frames per clientburst 5, 2/sec sustained
Lookups per clientburst 2, 1 every 2 sec sustained
Max frame size4 KB
Message buffer per recipient32 messages

Exceeding the per-IP connection limit returns HTTP 429. Exceeding per-client limits returns a WebSocket error frame.

Errors

MessageCause
Bad token.Invalid or corrupted ?token= value (close code 4000)
Token already in use.Another connection is already using this token (close code 4000)
Frame too largePayload exceeds 4 KB
Rate limitedToo many requests
Expected JSON objectFrame was not a JSON object
Missing or invalid 'type' fieldNo type string in the object
Missing or invalid 'code' fieldLookup without a valid code
Missing or invalid 'recipient' fieldMessage without a valid UUID recipient
Missing or invalid 'text' fieldMessage without a text string
Code not found: XXXXShare code does not exist or expired
Recipient not foundNo connected client with that UUID
Recipient busyRecipient's message buffer is full
Recipient disconnectedRecipient disconnected before delivery
No share codes availableCode space exhausted (unlikely)
Unknown message type: XUnrecognized type value

Open the browser console to use the built-in test client.