Skip to content
On this pageOPEN
  1. 01Goal
  2. 02Plain-language concept
  3. 03Interactive diagram
  4. 04Behind the scenes
  5. 05Code walkthrough
  6. 06Do & don't
  7. 07Practice
  8. 08Quick quiz
  9. 09Key takeaways
  10. 10Common errors
LESSON 07Advanced38 min read

ICE, STUN, TURN: finding a path

How peers discover addresses, traverse NAT, run connectivity checks, and fall back to a relay when nothing else works.

#ICE#STUN#TURN#NAT#candidates
01

Goal

  • 01Explain why two browsers behind NAT cannot simply connect to each other's private addresses.
  • 02Use host, server-reflexive, peer-reflexive, and relay candidates without confusing what each one proves.
  • 03Read an ICE trace, identify the selected pair, and know when TURN is mandatory rather than optional.
02

The concept, plainly

lets many private devices share one public address. A peer can open an outbound connection, but another peer cannot magically dial `192.168.1.20` on a different network. solves this by gathering several candidate addresses, exchanging them through signaling, and testing pairs until one path works. It is a connectivity search, not a single protocol message.

Candidate types tell you how an address was discovered. A **host** candidate is a local interface address. A **server-reflexive** (srflx) candidate is the public mapping a server observed. A **peer-reflexive** (prflx) candidate is a mapping discovered during connectivity checks that was not signaled. A **relay** candidate is a TURN allocation. More candidates mean more chances, not a guaranteed path.

is deliberately small: it reports the source address a server sees and helps keep NAT bindings open through connectivity checks. It does not relay media. If both peers are behind symmetric NAT or UDP is blocked, the direct pairs will fail. allocates a relay address, and both peers send media through that server. It works almost anywhere, costs bandwidth, and adds latency.

The selected pair is the one ICE nominates and the transport actually uses. Look at `getStats()` candidate-pair `nominated` and `selected`, or the transport's `selectedCandidatePairId`. Seeing a relay candidate in the list does not mean the call uses TURN. A direct host or srflx pair may win the checks first. Conversely, a call can work in the lab on one network and fail in a restrictive one without TURN configured.

Trickle ICE sends candidates as they are discovered, so media can start sooner. Non-trickle gathering waits for the complete candidate set and puts it in SDP. Both are valid. If candidates arrive before the remote description, queue them. When gathering finishes, an empty candidate event means complete, not failure. An `icecandidateerror` event names a STUN or TURN server problem.

When a network changes, call `restartIce()`, create a new offer, and let ICE find a fresh path. TURN credentials should be short-lived and issued by your own server; never ship a permanent TURN secret to the browser. Design for failure: show 'checking,' 'connected,' and 'failed' honestly, collect TURN usage metrics, and do not claim 'peer-to-peer' if every call is relayed.

03

See it move

PLAY / PAUSE / STEP

Interactive diagram

How ICE finds a path across two NATs

binding requestcandidatesmapped addresschecksfallbackrelayed SRTPnominated pairBROWSERPeer Aprivate networkNETWORKNAT Apublic mappingSERVERSignalingswap candidatesSERVERSTUNwhat am I outside?PROCESSPair checksSTUN binding requestsNETWORKNAT Bdifferent mappingSERVERTURN relayallocation + mediaNETWORKSelected pathSRTP over UDP/TCPPEERPeer Bprivate network
STEP 01 / 06host

Gather local host candidates

The browser lists private interface addresses. They can connect peers on the same LAN, but are usually unroutable across the internet.

Gather candidates, exchange them through signaling, test pairs, and nominate one. STUN discovers; TURN relays.

04

Behind the scenes

01

NAT mapping is not one behavior

Full-cone, restricted-cone, port-restricted, and symmetric NATs map and filter differently. A STUN-discovered port may work for one remote endpoint but not another. That is why a call can connect to one friend and fail to another from the same laptop. ICE tests the actual peer pair; STUN alone only predicts reachability from the server's viewpoint.

02

Candidate priority is a suggestion

ICE orders pairs by candidate type and priority, usually preferring host over srflx over relay. But the selected pair is the one that succeeds and gets nominated, not necessarily the first in the list. Mobile networks, VPNs, and firewalls can reorder the practical outcome. Always read the selected pair from stats rather than inferring from candidate order.

03

TURN is a production requirement

A lab without TURN can feel like WebRTC is broken when only one network is restrictive. Real products plan TURN capacity, credentials, and cost from day one. Relay usage can be a significant share of calls in enterprise and mobile networks. Metric it, geo-distribute relays, and issue credentials short-lived so a leaked config expires.

05

Code walkthrough

COPY-READY

Use coturn's shared-secret REST scheme. The browser gets a username and HMAC credential that expire; the permanent secret stays on the server.

app/api/turn/route.ts
import { createHmac } from "node:crypto";
export async function GET() {
const secret = process.env.TURN_STATIC_SECRET;
const turnUrl = process.env.TURN_URL;
if (!secret || !turnUrl) {
return Response.json({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] });
}
const ttl = 60 * 60;
const expiry = Math.floor(Date.now() / 1000) + ttl;
const username = `${expiry}:learn0`;
const credential = createHmac("sha1", secret)
.update(username)
.digest("base64");
return Response.json({
iceServers: [
{ urls: "stun:stun.l.google.com:19302" },
{ urls: turnUrl, username, credential },
],
ttl,
});
}
06

Do and don't

Do

  • Run TURN from the start

    A direct path is an optimization, not a guarantee. Test with a restrictive network or forced relay before you assume connectivity is solved.

  • Expose the selected pair

    Show whether a call is direct or relayed in diagnostics. This shortens support conversations and reveals TURN cost patterns.

  • Queue candidates and handle errors

    Candidates can race descriptions, and individual STUN/TURN servers can fail. Treat both as normal protocol states.

  • Restart ICE on network change

    Switching Wi-Fi, cellular, or VPN changes the path. Restart ICE with a new offer rather than silently freezing.

Don't

  • Don't call STUN a relay

    STUN discovers an address; it does not carry media. If both peers need a relay, only TURN helps.

  • Don't ship static TURN secrets

    A browser is not a secret store. Use expiring credentials minted by your server and rotate the shared secret.

  • Don't assume connected means direct

    A connected call can be relayed. Read the selected pair before making latency or privacy claims.

  • Don't rely on one STUN URL

    STUN outages and blocked servers happen. Configure redundancy and let candidate gathering continue even if one server fails.

07

Practice

Hands-on lab

Watch a path get chosen

The 1:1 lab lists every candidate, marks dropped ones, and reads the selected pair from live getStats. Use the filters to make direct paths fail.

  1. 1Connect two tabs normally and locate the selected pair's candidate types.
  2. 2Set the filter to TURN-only with no TURN configured, reset, and watch the connection fail in checking.
  3. 3Restore normal, reconnect, and confirm media returns.
  4. 4Read the ICE event log and explain why a candidate can be present but not selected.
Open the ICE lab

Solo? Loopback still gathers host candidates and runs the same ICE state machine. Filters such as TURN-only will make the local connection fail too.

08

Quick quiz

Knowledge check

0 of 4 answered

0%
  1. 01

    What does a server-reflexive candidate prove?

  2. 02

    When is TURN required?

  3. 03

    Which stats field identifies the nominated pair currently used by the transport?

  4. 04

    What should happen when a remote candidate arrives before setRemoteDescription?

Pick one answer per question to see instant feedback.
09

Key takeaways

  1. ICE searches candidate pairs; STUN discovers a public view; TURN relays when direct paths fail.01
  2. Host, srflx, prflx, and relay are different kinds of possibility, not different qualities of the same address.02
  3. The selected pair in getStats is the truth about direct versus relayed media.03
  4. Production WebRTC plans for TURN credentials, relay cost, candidate ordering, and network changes.04
10

Common errors and fixes

Terms in this lesson

Done with this lesson?

Mark it complete, then keep the thread.