What Is This?
meetX is a real-time peer-to-peer video calling web application, similar to Google Meet, built entirely from scratch. Users can sign up, create or join rooms, and have multi-participant video calls — all powered by browser-native WebRTC with a custom Socket.IO signalling server.
Tech Stack
Frontend: Remix v2, React 18, TypeScript, Tailwind CSS, Shadcn UI, WebRTC, Socket.IO Client
Backend: Express.js, Socket.IO, Redis, JWT (HTTP-only cookies)
DevOps: GitHub Actions CI/CD, deployed on Render
How It Works
Multi-Peer Mesh Architecture
Every participant connects directly to every other participant via WebRTC , no central media server needed. The server acts purely as a signalling relay, forwarding SDP offers/answers and ICE candidates between peers. All audio and video flows peer-to-peer.
Room & Call Flow
- User creates or joins a room with a room ID
- Server notifies existing peers about the new user and sends back the current peer list
- For each existing peer, the new user creates an
RTCPeerConnection, generates an SDP offer, and sends it via the signalling server - Existing peers respond with SDP answers completing the WebRTC handshake
- ICE candidates are exchanged for NAT traversal using Google's public STUN servers
- P2P video streams are established each remote track is rendered in a dynamically created
<video>element
Signalling Server
The Socket.IO server handles four core events — join-room, offer, answer, and ice-candidate. It maintains a server-side peers Map tracking connected users and their socket IDs. The server never processes media — it only relays signalling messages.
Authentication
Custom-built auth using Redis as the user store. Passwords are hashed, JWTs are signed and stored as HTTP-only cookies. Socket.IO connections are authenticated via middleware that parses the cookie from the WebSocket handshake and verifies the JWT.
Key Engineering Decisions
- Mesh topology — every peer connects to every other peer directly, avoiding the complexity of an SFU/MCU media server while keeping latency low for small rooms
- Module-level Maps for peer connections and video refs — stable references across React renders, avoiding stale closures in async WebRTC callbacks
- Singleton socket pattern — a single Socket.IO connection reused across the entire app
- Remix loaders/actions for server-side auth checks and redirects, cleanly separating concerns from client-side WebRTC logic
- Redis hashes as a lightweight user store — no schema migrations, no ORM overhead
What I Learned
Building meetX gave me deep hands-on experience with WebRTC internals — SDP negotiation, ICE candidate exchange, STUN/NAT traversal, and managing multiple peer connections simultaneously. It also reinforced my understanding of real-time signalling architectures and the challenges of coordinating state between server-side socket rooms and client-side peer connection maps.