WebRTC Signaling
The signaling service coordinates WebRTC peer connections between devices in the same household. It is control-plane only: it relays signaling messages needed to establish peer connections, but it does not carry application data.
Endpoint
WebSocket: /ws/signal
Join Authorization
In self-hosted mode (authMode = NONE), joins are accepted without hosted auth checks.
In hosted mode (authMode = SUPABASE):
- the client authenticates first
- the client fetches
GET /api/household - the client sends
Join(deviceId, householdId, accessToken) - the server verifies the Supabase access token
- the server looks up the caller's authoritative
user_profiles.household_id - the join is accepted only when the requested household matches the hosted metadata
This prevents hosted clients from joining arbitrary households by supplying a different householdId.
How It Works
- A device connects to the WebSocket and sends a
Joinmessage with itsdeviceIdandhouseholdId - The server registers the device and responds with a
PeerListof other connected devices in the household - Existing peers receive a
PeerListnotification with the new device's ID - Devices exchange WebRTC offers, answers, and ICE candidates through the server relay
- Once a direct peer connection is established, sync data flows over WebRTC data channels
Message Types
| Message | Direction | Purpose |
|---|---|---|
Join | Client → Server | Register device in household |
PeerList | Server → Client | List of connected peer device IDs |
Offer | Relayed | WebRTC SDP offer |
Answer | Relayed | WebRTC SDP answer |
IceCandidate | Relayed | ICE candidate for NAT traversal |
Allowed signaling traffic is limited to:
JoinPeerListOfferAnswerIceCandidate
The server only relays signaling-plane messages needed to establish WebRTC peers. User data does not traverse the signaling WebSocket.
Disconnection
When a device's WebSocket closes, it is unregistered from the household. Remaining peers discover the disconnection through their own WebRTC connection timeouts.
