Wire protocol

Everything on the socket is a short text frame: a number, a colon, then the details. You only need this page to write a client for another language or to read the wire log in the demos.

Connecting

Open a WebSocket to wss://ws.pikoman.se/{appId}. The first frame you receive carries your connection id:

042

Opcodes

Code Meaning Client sends Server sends
0 Connection Never 0:{connectionId}
1 Server message Never 1:{channel}:{event}:{payload}
2 Subscribe 2:{channel}
2:{channel}:{signature}:{permissions}:{data} for presence
2:{channel} as confirmation
2:{channel}:{count}:{connectionId}:{data} when a member joins
3 Join refused Never 3:{channel} when a presence signature is wrong
4 Unsubscribe 4:{channel} 4:{channel} as confirmation
4:{channel}:{count}:{connectionId} when a member leaves
8 Client message 8:{channel}:{toAll}:{event}:{payload} 8:{channel}:{senderId}:{event}:{payload}
9 Rate limited Never 9:RATE_LIMIT
16 Member list Never 16:{channel}:{members} after a presence join
64 Ping 64:{timestamp} The same frame, echoed

Only the first colons separate fields. The last field runs to the end of the frame, so payloads may contain colons freely.

A presence session, frame by frame

Connection 42 joins a room that already has one member, says hello, and receives a message published over HTTP.

Direction Frame What happened
Received 0:42 Connected, and this is our id.
Sent 2:presence-room:9f2c…e1:3:{"name":"Ada"} Join, with the string our backend signed.
Received 16:presence-room:{"17":"{\"name\":\"Linus\"}","42":"{\"name\":\"Ada\"}"} Everyone in the room, including us. Each value is that member's data as a JSON string.
Sent 8:presence-room:1:message:{"text":"hello"} A client message. toAll is 1, so we get it back as well.
Received 8:presence-room:42:message:{"text":"hello"} The relayed message, now carrying the sender's id.
Received 1:presence-room:bot:{"text":"Welcome, Ada"} A server message, published with POST /presence-room/bot.
Received 4:presence-room:1:17 Linus left. One member remains.

Keeping the connection alive

The server echoes any frame it does not otherwise understand, which is how ping works. The JavaScript client sends 64:{timestamp} after 6.5 seconds without traffic and reconnects if nothing arrives for 18.5 seconds. A client you write yourself should do something similar.

Limits

  • Client messages need a presence channel and a join signed with write permission.
  • One client message per connection every 20 ms. Extra ones are dropped and answered with 9:RATE_LIMIT.
  • Server messages cannot be sent over the socket. They come from the HTTP API only.

Previous: publishing over HTTP See it live in the demos

We are rebuilding the dashboard

Self-service sign-up is closed while we do. Until the new dashboard is ready we set up apps by hand: write to us with a line about what you are building, and we will send you an app id and a secret.

Write to hello@pikoman.se