Prompt
How do I use TURN and STUN for browser video calling
Latest observation
Oct 6, 2026
OpenAI APIWeb search: off
To use STUN and TURN for browser-based video calling, you typically configure them in WebRTC.
What they do
- STUN helps a browser discover its public IP address and NAT type.
- TURN relays media when direct peer-to-peer connection fails, which is common with strict NATs/firewalls.
Typical setup
In a browser video call, you create an RTCPeerConnection and pass ICE servers:
const pc = new RTCPeerConnection({
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
},
{
urls: 'turn:turn.example.com:3478',
username: 'myuser',
credential: 'mypassword'
}
]
});
How it works
-
Get media
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); stream.getTracks().forEach(track => pc.addTrack(track, stream)); -
Create offer/answer
- One peer creates an offer:
const offer = await pc.createOffer(); await pc.setLocalDescription(offer); - Send the offer to the other peer through your signaling server.
- One peer creates an offer:
-
Exchange ICE candidates
- Listen for candidates:
pc.onicecandidate = event => { if (event.candidate) { sendToPeer({ candidate: event.candidate }); } }; - Add candidates from the remote peer:
await pc.addIceCandidate(remoteCandidate);
- Listen for candidates:
-
Use TURN when needed
- The browser first tries direct connections.
- If that fails, it can route media through TURN automatically if configured.
Important notes
- STUN alone is not enough for many real-world calls; TURN is needed for reliability.
- Use
turns:for TURN over TLS if possible:urls: 'turns:turn.example.com:5349' - TURN servers need valid usernames/passwords or time-limited credentials.
getUserMediaand many WebRTC features require HTTPS.
Minimal example
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{
urls: 'turn:turn.example.com:3478',
username: 'user',
credential: 'pass'
}
]
});
const localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
localStream.getTracks().forEach(track => pc.addTrack(track, localStream));
pc.ontrack = event => {
document.querySelector('#remoteVideo').srcObject = event.streams[0];
};
pc.onicecandidate = event => {
if (event.candidate) {
// send candidate to remote peer via signaling
}
};
Summary
- STUN: helps discover addresses
- TURN: relays media when direct connection fails
- Both are configured in
RTCPeerConnection.iceServers - You still need a signaling server to exchange offers, answers, and ICE candidates
If you want, I can also give you:
- a complete two-peer WebRTC example, or
- a production TURN server setup using coturn.
Brands