Building a Real-Time Collaborative E-Learning Platform with WebSockets
Building a Real-Time Collaborative E-Learning Platform with WebSockets
E-learning is broken when the classroom isn't live. Here's how I built a platform where students and instructors collaborate in real time.
The problem
Polling sucks. Traditional HTTP requests waste bandwidth and battery. For a classroom with 40 students, polling every 500ms means 1,440 request/min per student—that's 57,600 requests hitting a single server every minute just to check if anything changed.
The solution: WebSockets + Redis
Socket.io for persistent bidirectional connections
- Auto-reconnection on network drop
- Rooms for class isolation (each classroom is a room)
- Fallback to long-polling for networks that block WebSockets
Redis pub/sub to scale beyond a single server
- Instructor broadcasts → Redis → all connected students
- Scales horizontally (add servers, they all sub to same Redis channel)
- Persistence for replay (store messages, let latecomers catch up)
React hooks for synced UI state
useEffectlistens to socket events and hydrates local state- Optimistic UI: student drags a whiteboard stroke → emits immediately, UI updates now (doesn't wait for server ack)
- Conflict resolution: if two students draw at same pixel, last-write-wins (simpler than CRDT for a classroom)
Architecture
Instructor Browser
↓ (socket.emit('broadcast_slide_change'))
Socket.io Server (Node.js)
↓ (redis.publish('classroom:42', { slide: 3 }))
Redis Pub/Sub
↓ (distributes to all servers listening on 'classroom:42')
Socket.io Server Replicas
↓ (socket.emit('slide_changed', { slide: 3 }))
Student Browsers (40 tabs connected to any server)
The hard parts
Latency: Over cellular, round-trip to instructor's broadcast can be 500ms+. Students see the instructor move before the whiteboard updates. We solved this with predictive rendering — students draw locally first, server acks 50ms later, and if positions diverged, we tween back.
Dropped sockets: WiFi kicks students mid-class. On reconnect, they need to re-enter the room and catch up on the last 2 minutes of content. We store the last 100 events in Redis and replay them.
Cost: Every persistent connection is memory. At peak, we had 200 classrooms (8,000 students). Each socket takes ~2 KB of state. That's 16 MB just for socket metadata. Proper Redis tuning + connection pooling was essential.
Results
- Latency: <100ms from instructor action to student's UI update (90th percentile)
- Concurrent: 8,000 students across 20 classroom instances
- Cost: $400/mo for Socket.io servers + $150/mo for Redis cluster
Polling this scale would have been 10x the server cost.
If you're building real-time features, the key insight is: persistent connections are cheaper than polling at scale. The upfront investment in WebSockets + Redis pays off immediately once you exceed 50 concurrent users.
See the full code and live demo at my portfolio.
