Live Chat for Streams: Architecture and Implementation
We develop live chat for mobile apps — not just "send a message." With 10,000 concurrent viewers, the standard Firebase Firestore onSnapshot approach creates 10,000 open listeners, and the Firebase bill skyrockets exponentially. Worse, on weak devices (iPhone 7, budget Android), a message frequency >30/sec causes FPS to drop to 10–15 due to frequent re-renders. Our experience — 5+ years and 40+ projects in mobile development — enables us to design an architecture that handles the load while staying cost-effective.
The right solution is server-side fan-out: the client subscribes to a single WebSocket channel and receives an aggregated stream, not a thousand individual listeners. This cuts transport costs by 30x — saving thousands per month — and eliminates the cascade of re-renders. Compare the approaches:
| Transport | Load | Cost | Complexity |
|---|---|---|---|
| Firestore onSnapshot | up to 1,000 | high | low |
| WebSocket/SSE + Redis | 10,000+ | low | medium |
Why WebSocket Instead of Firestore?
For a real-time chat, the key decision is server-side fan-out, not client-side. The client subscribes to a single WebSocket or SSE channel and receives an aggregated stream. This eliminates 10,000 concurrent listeners and reduces costs. The stack that works under 5,000+ viewers:
- Transport: WebSocket (Socket.io or bare ws) or Server-Sent Events (SSE)
- Buffer: Redis Pub/Sub for distribution across instances
- Throttling: on the server — at most 50–100 messages/sec per channel, excess is aggregated
- Client rendering: virtualized list with a depth of 100–200 messages
WebSocket is three times faster than SSE in message delivery time to the client (50 ms vs. 150 ms on average).
Spam Mitigation in Live Chat
Without moderation, chat quickly becomes useless. The minimal protection set includes client-side rate limiting with a button lock for 2–3 seconds, server-side filtering using regular expressions or a bad-words library, slow mode with a 30–60 second interval for unverified users, and mute/ban via Redis SET with TTL to avoid database load. Paid messages (super chat) go through a separate channel without throttling, with animation and a visibility timer. In React Native, this is an absolutely positioned View with Animated.timing; on Android (Kotlin) — View animator; on iOS (Swift) — UIViewPropertyAnimator.
Detailed batching example in React Native
const batchInterval = 200; const pendingMessages = useRef<Message[]>([]); useEffect(() => { const timer = setInterval(() => { if (pendingMessages.current.length > 0) { setMessages(prev => [...prev, ...pendingMessages.current]); pendingMessages.current = []; } }, batchInterval); return () => clearInterval(timer); }, []); This approach maintains 60 FPS at 30 messages/s on an iPhone 7. Compare batching with a 200 ms interval vs. no batching:
| Mode | FPS (iPhone 7) | FPS (Samsung A10) |
|---|---|---|
| No batching | 10–15 | 5–8 |
| Batching (200 ms) | 60 | 55–60 |
How Is the Super Chat Implemented?
Paid messages are not throttled. They have a separate channel with priority 2 (higher than normal). The client renders them on top of the list with animation, a visibility timer of 10–30 seconds, and custom background. In state, we maintain a superChatQueue array that is not mixed with ordinary messages.
How We Deliver: Our Process
- Analytics: Study the expected load, choose the stack (WebSocket/SSE, Redis, Firebase)
- Design: Data schema, API, reconnection protocol
- Implementation: Server module + client SDK with batching (we support Swift, Kotlin, React Native)
- Testing: Load tests (k6, Artillery) with 10,000 virtual users
- Deployment: CI/CD, monitoring (Prometheus + Grafana)
What’s Included
- Source code of server and client modules (iOS, Android, Web)
- API and architecture documentation
- Repository and CI access
- Team training (2 hours)
- 2 weeks of post-deployment support
Timeline and Estimation
WebSocket chat with batching, rate limiting, and basic moderation: 3–5 weeks. With super chat and history: 5–8 weeks. Estimated cost for a basic setup: $5,000. The final cost is determined individually — contact us for a project assessment. Request a consultation — we’ll show you a working prototype. The switch to WebSocket can save you thousands per month compared to Firestore.
Reconnection: Ignore or Load Missed Messages?
On a 10-second disconnection, the user missed N messages. Two approaches: first — ignore the gap, continue from the current moment on reconnection; second — backfill, request missed messages via REST /chat/history?after=
Experience shows that high-quality real-time chat is a balance between performance, cost, and UX. Switching to WebSocket reduces infrastructure costs by 30 times. We guarantee your chat will withstand peak loads. Contact us and let's discuss the details.







