Social LiveDocumentationPLATFORM DOCS

Realtime (Socket.IO)

The always-on channel that powers live rooms and chat, and the rules that keep it consistent.

Last updated Thu Jul 16 2026 00:00:00 GMT+0000 (Coordinated Universal Time)

TL;DR -Alongside ordinary requests, the backend keeps a live connection open to each app so it can push updates the moment they happen — a viewer joining, a gift animation, a new chat message. Money always moves over the ordinary request path first; the live channel only announces what already happened.

Who this is for -Product & Business: read "What realtime is for" for the concept. Engineering & Backend: the two gateways, the fan-out model, and the ordering/delivery rules.

What realtime is for

Some things can't wait for the app to ask again. When a gift lands or a viewer joins, everyone in the room should see it instantly. To make that possible, the app opens one always-on connection to the backend and leaves it open for the whole session. The backend can then push events down that pipe the instant they occur.

The technology behind this is Socket.IO, a library for two-way, real-time messaging over a WebSocket (a persistent connection, unlike a normal request that opens, answers, and closes). The Flutter app keeps one socket per session (lib/modules/signaling/), authenticated with the same JWT login token it uses for ordinary requests.

The backend organizes this real-time work into gateways -the socket equivalent of the controllers used for ordinary requests. There are two.

Gateways

LiveGateway (backend/src/modules/live/live.gateway.ts)

Handles everything that happens inside a live room in real time:

  • Presence -join/leave events maintain the room's viewer and participant counts; the service reconciles viewerCount with the actual gateway audience so counts cannot drift. Each viewer_joined/viewer_left event carries an authoritative audienceCount (the deduped live audience computed after the socket (un)registered); clients display that value verbatim rather than applying local +/-1 deltas, which previously drifted when events were missed or arrived out of order.
  • Stage management -guest requests, host approval, guest media choices (audio-only vs audio+video), stage position updates.
  • Gift broadcast -after the REST gift-send succeeds (money moves over REST, never over the socket), the gift event is fanned out to the room so every viewer sees the animation.
  • PK battles -battle start/score/end updates.
  • Producer resync -when a host or guest publishes a new media track, other clients are told to consume it; clients skip producers they own.
  • Actor names -the JWT carries only the user id, so the gateway resolves the sender's profile displayName once per socket (cached on the socket) and stamps it on chat, reactions, stage requests, and gifts. Anonymous sockets fall back to "Viewer".

ChatGateway (backend/src/modules/chat/chat.gateway.ts)

  • Message delivery into conversation rooms.
  • Typing indicators (chat:typing_started / stopped).
  • Read receipts.

Room naming & fan-out

"Fan-out" means delivering one event to many connected clients at once. To keep that efficient, the backend groups sockets into rooms -one per live room or conversation -and only sends an event to the sockets that are actually in it.

Socket.IO rooms are keyed by domain id (live room id, conversation id). A client joins the socket room when it enters the screen and leaves when it navigates away, so fan-out cost tracks actual audience.

Ordering and delivery rules

Live connections are inherently unreliable -sockets drop, events arrive late or out of order. These rules make sure that never corrupts real state, especially anything involving money.

  • Money over REST, events over sockets. A gift is charged via POST /wallet/gifts/send (idempotent, transactional) and only then announced via the gateway. If the socket drops, the money is still correct and the UI catches up on next fetch.
  • Reconnection -socket_io_client auto-reconnects; on reconnect the client re-joins its rooms and re-syncs state via REST (single source of truth), so missed events cannot corrupt state.
  • Diagnostics -with ENABLE_LIVE_DIAGNOSTICS=true, room lifecycle events are persisted to LiveRoomEventLog and surfaced in the admin diagnostics page. Payloads are sanitized before storage.

The QA simulator

Testing real-time behavior on real phones is slow, so there's a stand-in. tools/live-room-simulator/ is a Next.js console that speaks the same Socket.IO + mediasoup protocol as the mobile app. Use it to exercise signaling, publish test media, and watch viewer consumption without any device -invaluable for regression-testing gateway changes.