WebRTC tutorials show you how to connect two browsers on localhost. Production deployments are different. Here is what you need to know before you ship.
The WebRTC tutorials are good. They walk you through creating a RTCPeerConnection, setting up a local signaling mechanism, exchanging SDP and ICE candidates and establishing a peer connection. You run it in two Chrome tabs on the same machine, video appears and it feels like a solved problem.
Then you try to connect two real users on real networks and discover how much the tutorial left out.
WebRTC is peer-to-peer, which means the two clients need to establish a direct connection. The problem is that most endpoints are behind NAT routers - a mechanism that assigns private IP addresses to devices and maps them to a shared public IP. NAT was not designed for inbound connections and WebRTC needs inbound connections.
ICE (Interactive Connectivity Establishment) is the framework WebRTC uses to find a path between two peers. It tries candidate types in preference order:
In controlled tests on typical home broadband, STUN succeeds often. In enterprise networks with stricter NAT, corporate firewalls and proxies, STUN fails far more often than expected.
The practical rule: if you care about connection reliability, you need a TURN server. STUN-only deployments leave a predictable percentage of enterprise users unable to connect.
TURN relay passes all media traffic - both directions - through the TURN server. For video calls at typical resolutions, this is 1-3 Mbps per session. The bandwidth cost is the primary TURN operational cost and it is real.
Sizing a TURN server involves estimating your concurrent relay session load and allocating bandwidth accordingly. COTURN, the open-source TURN server, is reliable and well-maintained. Running it on an undersized instance causes quality degradation at exactly the moments when users are already struggling - NAT traversal failed, the call is on a relay path and now the relay is under resource pressure.
If you're using a managed WebRTC service that includes TURN, understand their bandwidth pricing model before you scale.
WebRTC needs a signaling channel to exchange session setup information before the peer connection is established. The tutorials usually use a WebSocket server for this. In production:
The signaling server failure mode is worth thinking about early. If the signaling server goes down after a connection is established, the peer connection continues - WebRTC is resilient once connected. But any reconnection attempt during an outage will fail silently from the user's perspective.
WebRTC on Android and iOS works, but the implementation details diverge from the browser significantly enough that treating mobile as "the same as web" is a mistake.
Browser WebRTC is implemented natively. Mobile WebRTC uses the libwebrtc library, which requires integration effort. The library handles codec negotiation, but the specifics of codec preference, bandwidth adaptation behaviour and how the library interacts with the platform's audio session APIs vary enough between Android and iOS that you should budget separate debugging time for each.
iOS has specific requirements around audio session interruptions - phone calls, system notifications, AirPods switching - that need explicit handling. Getting this wrong produces audio dropouts that are difficult to diagnose because they are triggered by external events rather than your code.
Chrome, Firefox and Safari all implement WebRTC but they don't implement it identically. Safari has historically lagged in WebRTC support and has specific behaviours around SDP format, codec support and permission handling that require browser-specific treatment.
Test your implementation in all target browsers before declaring it done. The cases that fail in Safari specifically tend to be subtle - the connection succeeds but audio is muted, or screen sharing doesn't work - rather than outright failures that are easy to catch.
A minimal production setup requires:
Beyond minimal:
WebRTC is genuinely powerful and browser support is good enough for production use. The gap between a tutorial demo and a production deployment is mostly operational - infrastructure, failure handling and mobile edge cases - rather than protocol-level complexity. Plan for it.