Skip to content

How WebRTC actually connects two browsers

NAT, STUN, candidates, signalling, hole punching and ICE — the real sequence that lets two browsers behind separate routers send video directly to each other, and what happens when it fails.

Last updated

Two browsers, on opposite sides of the world, behind separate home routers that both block incoming connections, somehow end up sending video directly to each other in about two seconds. Nobody configured a port. Neither has a public address of its own.

This is how that actually happens, in the order it happens, without hand-waving at the parts people usually skip.

The problem: neither of you has an address

Your laptop does not have an address the internet can reach. It has a private address handed out by your router — something in the 192.168 range — and the router owns the single public address your whole household shares. This is called NAT, network address translation, and it exists because the world ran out of IPv4 addresses long ago.

NAT is fine for browsing, because you start every conversation. Your router remembers that you asked a website for something and lets the reply back in. It is fatal for two peers trying to reach each other, because neither side has been asked for anything, and both routers drop the unsolicited packet.

Step one: discovering how the world sees you

Your browser asks a STUN server a single question: what address did this packet appear to come from? The STUN server sees the public address and port your router assigned, and sends it back.

That pair — public address and port — is a candidate: one possible route to you. Your browser gathers several. The private address on your local network, in case you are both on the same Wi-Fi. The public one STUN discovered. Sometimes others.

STUN traffic is tiny, it carries no media, and the server learns nothing but that somebody asked. Mulaqat uses public STUN servers from Cloudflare and Google.

Step two: the introduction

Both browsers now hold a list of candidates and a description of what they can send — codecs, resolutions, whether there is audio. None of that is any use unless the other side receives it, and the two peers still cannot talk to each other. Something in the middle has to carry the introduction.

That is signalling, and it is the part WebRTC deliberately does not specify. Any channel will do. Mulaqat uses a WebSocket to a server that holds the lobby, which passes messages between exactly two sockets it has already paired.

The exchange itself is short:

  1. One side creates an offer describing what it can send, and sends it through the server.
  2. The other replies with an answer describing what it accepts.
  3. Both send their candidates as they are discovered, rather than waiting for a complete list.

The server relays these blobs without needing to understand them. On Mulaqat the payload is treated as opaque: the server vouches for who sent a message, not for what is inside it.

Step three: punching through

Now the clever part. Each browser starts sending small probe packets to every candidate the other offered, at the same time, in both directions.

When your browser sends a probe outward to their address, your router sees an outgoing packet and creates a temporary rule: replies to this destination are expected, let them back in. Their router does the same. Neither side was reachable a moment ago, and now both are — because they each opened the door from the inside, simultaneously.

This is hole punching, and the whole process of trying every combination until one works is called ICE. Several pairs may succeed; ICE picks the best and the rest are discarded.

Step four: the media flows, encrypted, and not through us

Once a candidate pair wins, video and audio travel over it directly. WebRTC does not offer an unencrypted mode — media is protected by DTLS-SRTP with keys negotiated between the two browsers, and encryption is mandatory rather than a setting somebody can turn off.

On Mulaqat the server has now left the conversation entirely. It carried a few small text messages to introduce two browsers and it holds no part of the media path. That is the whole reason we can say calls are not recorded: not that we choose not to, but that no recordable copy ever reaches us. The longer version, including what it does not protect you from, is in what peer to peer actually means for your privacy.

When hole punching fails

It does not always work. Symmetric NAT — common on corporate networks and some mobile carriers — assigns a different external port for every destination, so the address one side was told to use is already wrong by the time the other tries it. Strict firewalls block the probes outright.

The standard answer is a TURN server, which relays media when a direct path cannot be found. It fixes connectivity on almost any network, and it costs real money per gigabyte, because every byte of every call passes through it. It also puts a server back in the media path.

Mulaqat ships with TURN disabled. On a small number of networks that means a connection fails, and when it does we say so plainly and offer the next person rather than showing a black rectangle. It is a deliberate trade: a few failed connections in exchange for a promise about recording that does not depend on trusting us.

Watch it happen yourself

Open chrome://webrtc-internals in another tab during any WebRTC call, on any site. You will see the peer connection, the candidates gathered, and which pair won.

The candidate type is the interesting field:

  • host — a direct local address. You are on the same network.
  • srflx — server reflexive, the public address STUN discovered. Hole punching worked.
  • relay — a TURN server is forwarding your media. Something in the path can see it.

On Mulaqat it will never say relay, because there is no relay to use. That is a claim you can check in about fifteen seconds rather than take on faith, which is rather the point.

If a call will not connect for you, the cause is more often a permission than a network — eight reasons a camera will not start goes through those in order.