Architecting a Real-Time Frontend for WebRTC Applications
Real-time applications are unforgiving.
Latency is visible.
State inconsistencies are obvious.
Poor UX decisions are amplified.
When building Medivue, a doctor–patient communication platform with chat, voice, and video, I learned quickly that real-time frontend architecture is less about APIs and more about predictability, resilience, and user perception.
This article breaks down how I think about real-time frontends—specifically for WebRTC-based applications.
Real-Time Frontend Is a System, Not a Feature
In traditional web apps:
- • UI reacts to user actions
- • Backend responds
- • State flows in one direction
In real-time apps:
- • State changes without user input
- • Network conditions are unstable
- • Multiple systems compete to update the UI
This changes everything.
The frontend becomes an orchestrator, not just a renderer.
Managing Real-Time State Without Losing Control
The Core Problem
In WebRTC applications, state comes from multiple sources:
- →User interactions
- →Signaling server (Socket.IO)
- →Peer connection events
- →Media device changes
- →Network interruptions
If all of this flows directly into React state, chaos follows.
The Approach I Took
I separated state into three clear layers:
UI State
- • Modals
- • Button states
- • Local UI feedback
Session State
- • Call status (idle, ringing, connected, ended)
- • Participant roles
- • Permissions
Connection State
- • WebRTC peer status
- • ICE connection state
- • Media stream readiness
Each layer had clear ownership and limited responsibility.
This prevented cascading re-renders and made debugging far easier.
Handling Latency in the UI (Not Just the Network)
Latency is inevitable.
Bad UX is not.
Common Mistake
Waiting for server confirmation before updating the UI.
This makes interfaces feel slow—even when the backend is fast.
What Worked Better
I adopted optimistic UI updates wherever possible:
- ✓Button feedback happens immediately
- ✓UI reflects intent, not confirmation
- ✓Backend failures are handled gracefully after
Example: When a user initiates a call:
- 1. UI transitions to "Calling" instantly
- 2. Ringing indicators appear
- 3. Connection events update the UI progressively
The user never feels like the app is "thinking".
UX Considerations for Calls and Chat
Real-time UX is about clarity under uncertainty.
For Video & Voice Calls
Key principles:
- • Always show current state
- • Never leave the user guessing
- • Transitions matter more than visuals
Important details:
- • Clear "connecting" vs "connected" states
- • Visible mic/camera status
- • Explicit call ended feedback
Even a 1–2 second ambiguity creates anxiety in communication apps.
For Chat Interfaces
Chat is deceptively complex.
Things I accounted for:
- • Message ordering under latency
- • Temporary "sending" states
- • Clear sender identity
- • Persistent history across refresh
Chat UX must feel reliable, even when the network is not.
WebRTC Events Are Not UI Events
One of the biggest lessons from Medivue:
WebRTC events should never directly control UI.
Examples:
- • ontrack
- • onicecandidate
- • connectionstatechange
These events are technical signals, not UX decisions.
Instead:
Events update connection state
Connection state updates session state
Session state drives UI
This separation prevents UI flicker, race conditions, and inconsistent visuals.
Designing for Failure (Because It Will Happen)
Real-time apps fail in many ways:
• Network drops
• Peer disconnects
• Permissions denied
• ICE negotiation fails
Ignoring this leads to broken experiences.
I designed Medivue assuming:
- • Calls will fail sometimes
- • Users need clear recovery paths
- • Silence is the worst feedback
Every failure state had:
- ✓Explicit messaging
- ✓Clear next action
- ✓Calm, non-alarming tone
Performance Is Part of UX
In real-time applications:
- • Heavy animations hurt more than help
- • Frame drops during calls are unacceptable
- • Visual polish must never interfere with media streams
Because of this:
Animations were minimal during calls
Media components were isolated from re-renders
UI updates were intentional, not reactive
The call experience stayed stable and predictable.
Lessons Learned Building Medivue
If I had to summarize everything into a few principles:
→ Separate UI, session, and connection state
→ Design UX for uncertainty, not ideal conditions
→ Treat WebRTC events as data, not commands
→ Optimize for perceived responsiveness
→ Reduce visual noise during real-time interactions
Real-time systems reward clarity and restraint far more than cleverness.
Closing Thought
Architecting a real-time frontend isn't about mastering WebRTC APIs.
It's about understanding:
- •How users perceive delays
- •How systems fail
- •How to keep interfaces calm under pressure
Medivue reinforced something I now apply everywhere:
A stable UI builds trust faster than a flashy one.
Why This Matters in My Portfolio
This project demonstrates:
System-level frontend thinking
Real-time UX decision-making
Practical WebRTC experience
Performance-aware UI design
These are exactly the challenges modern product teams face.