Skip to content

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:

{
  "type": "join_room",
  "data": {
    "room_id": "room-abc"
  }
}

Server → Client (Success):

{
  "type": "room_joined",
  "data": {
    "room_id": "room-abc",
    "users": ["user1", "user2"]
  }
}

📝 Send a Chat Message

Client → Server:

{
  "type": "send_message",
  "data": {
    "room_id": "room-abc",
    "message": "Hello world!"
  }
}

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:

{
  "type": "error",
  "data": {
    "code": 4001,
    "message": "Room not found"
  }
}
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:

{
  "type": "send_message",
  "version": "1.0",
  "data": {
    ...
  }
}

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.