WebSocket Message Format
In a WebSocket-based system, messages are often exchanged in a structured format such as JSON. Designing a clean and consistent message format is essential for ensuring reliable, secure, and extensible communication between the client and server.
This page outlines the standard structure we use for messages, how to handle types, payloads, errors, and versioning.
🧱 Message Envelope
Each message follows a consistent JSON structure:
{
"type": "event_name",
"data": { ... },
"meta": {
"request_id": "uuid-123",
"timestamp": "2025-08-04T12:34:56Z"
}
}
Field Definitions
Field | Type | Required | Description |
---|---|---|---|
type |
string |
✅ | The event type or message name |
data |
object |
✅ | The payload relevant to the event |
meta |
object |
❌ | Optional metadata (e.g., timestamp, request ID) |
🎯 Example Messages
✅ Join a Room
Client → Server:
Server → Client (Success):
📝 Send a Chat Message
Client → Server:
Server → All Clients:
{
"type": "new_message",
"data": {
"room_id": "room-abc",
"user": "user1",
"message": "Hello world!",
"timestamp": "2025-08-04T12:35:10Z"
}
}
⚠️ Error Messages
Standard format for error responses:
Field | Description |
---|---|
code |
Numeric code for programmatic use |
message |
Human-readable explanation |
🛡️ Server-to-Client Event Types
Event Type | Description |
---|---|
room_joined |
Confirmation of room join |
new_message |
Broadcast of a new message |
user_typing |
Optional "user is typing" indicator |
error |
Error response |
ping / pong |
Heartbeat mechanism |
disconnect |
Server intent to close the connection |
🔁 Message Flow Example
Client: {"type": "join_room", "data": {"room_id": "abc"}}
Server: {"type": "room_joined", "data": {"room_id": "abc", "users": [...]}}
Client: {"type": "send_message", "data": {"room_id": "abc", "message": "Hi"}}
Server: {"type": "new_message", "data": {"room_id": "abc", "user": "...", "message": "Hi"}}
📦 Versioning (Optional)
If you expect future changes:
Use the version
field to gracefully handle schema evolution over time.
✅ Best Practices
- Always include a
type
field to define intent. - Keep payloads minimal and validate on both ends.
- Use UUIDs for correlation (
meta.request_id
) and ISO-8601 timestamps. - Define and document each event's payload clearly.
- Use structured error messages with consistent codes.
🔚 Next Steps
- Authentication: Secure your message flows.
- Clients: Implement this message format on the frontend.
- Events: Explore supported event types and flows.