guide

WebRTC Test Guide

A reference for the desktest.net WebRTC Test. Covers how it checks STUN reachability, ICE gathering, and an end-to-end peer connection, how to read the verdict, and what to do when video calls will not connect.

Open the WebRTC Test ->

What does the WebRTC Test check?

The tool drives the browser's RTCPeerConnection API against a set of public STUN servers, then negotiates a full connection between two peers inside the same page. It does not call getUserMedia, so no camera or microphone permission prompt appears. Works on Chrome, Edge, Firefox, and Safari. The three steps run in order:

  1. Feature detection. Confirms RTCPeerConnection, getUserMedia, and getDisplayMedia exist, then enumerates the audio and video codecs the browser advertises through RTCRtpReceiver.getCapabilities() (H264, VP8, VP9, AV1, Opus, and so on) and notes whether insertable streams are supported.
  2. STUN reachability. Creates an RTCPeerConnection pointed at four public STUN servers (Google, Cloudflare, Mozilla), opens a data channel, creates an offer, and listens for ICE candidates for about 5 seconds. Each candidate is categorized as host (your local network), srflx (your public address as seen by STUN), prflx, or relay (TURN). A pass needs at least one host and one srflx candidate, which proves outbound UDP to a STUN server left and came back.
  3. End-to-end negotiation. Spins up two RTCPeerConnection objects in the same page, shuttles the offer, answer, and ICE candidates between them in JavaScript (no signaling server), waits for both to reach connected, then round-trips a message over a data channel. This proves the local WebRTC stack can negotiate a full session without depending on any external peer.

When should I run this?

Scope: this tests browser WebRTC, which is what Google Meet, Microsoft Teams on the web, Slack Huddles, and Zoom-in-the-browser use. The native Zoom and Teams desktop apps use their own media engines, but the same firewall and UDP rules usually apply, so a blocked result here predicts trouble for both.

Reading the results

Step 1 lists the detected codecs as chips and flags whether getUserMedia and getDisplayMedia (screen share) are available.

Step 2 shows the gathered candidates by type with counts. host is your local network, srflx is your public address discovered through STUN, and relay would be a TURN candidate (the test uses no TURN server, so relay stays at zero). Your public IP is shown once at the top; the per-candidate list redacts public addresses so a screenshot does not leak them. The raw SDP offer and answer are available in the Show SDP dropdowns.

Step 3 shows the live connection and ICE state of both in-page peers, the setup time, and the data-channel round-trip time.

Each step row carries a status badge: Pending, Running, Pass, Warn, or Fail. On warn or fail the row expands with the diagnosis. The verdict panel at the top names the most likely cause and a recommended next step. Copy Diagnostic Report copies a plain-text summary: browser, codecs, candidate counts by type, per-step results, timings, and the diagnosis tag. Paste it into a ticket.

Common failures and fixes

The tool produces a named diagnosis for every failure path. Two of them look similar but mean opposite things, so read carefully.

webrtc-unsupported: WebRTC is not supported

No RTCPeerConnection object exists at all. The browser is too old, sandboxed, or running with WebRTC disabled by policy. Update to a current Chrome, Edge, Firefox, or Safari, or check the browser's policy settings.

getusermedia-unsupported: capture is unavailable

getUserMedia is not exposed, usually because the page is served over plain HTTP instead of HTTPS, or the browser is very old. On desktest.net the page is HTTPS, so this points at the browser. Core peer connection can still work; screen share or camera capture will not.

no-candidates: WebRTC is blocked at the browser level

No ICE candidates were gathered at all, not even a host candidate. That is not a firewall; a firewall still lets the browser see its own local addresses. This means WebRTC is disabled inside the browser.

  1. Retry in an incognito or private window with extensions disabled. Privacy extensions (uBlock Origin's "Prevent WebRTC from leaking local IP", Privacy Badger) and Brave Shields commonly cause this.
  2. On Firefox, check that media.peerconnection.enabled is true in about:config.
  3. On managed Chrome or Edge, check enterprise policy for a WebRTC block. If one machine fails here while its neighbor passes, it is local policy or an extension, not the network.

only-host: STUN servers are blocked

Local (host) candidates were discovered, but no public STUN endpoint answered, so no srflx candidate appeared. This is the classic corporate-network failure: a firewall is dropping outbound UDP to the STUN ports (3478 and 19302).

  1. Ask the network admin to allow outbound UDP to those ports.
  2. If the network refuses UDP as policy, the calling app needs a TURN relay (which can fall back to TCP or TLS on 443). This test includes no TURN server, so only-host is the honest result on such networks.
  3. Off the corporate network (phone hotspot, home wifi) the same test usually passes, which confirms the block is the network, not the machine.

setup-timeout: peers did not connect in time

The two in-page peers did not both reach connected within 8 seconds. Usually background-tab throttling, a slow machine, or an extension interfering. Keep this tab in the foreground, close other tabs, disable extensions, and retry.

ice-failed: ICE failed mid-negotiation

One of the in-page peers entered the failed ICE state. Because both peers are in the same tab, a network firewall cannot cause this; a privacy extension or strict policy is blocking candidate exchange even locally. Retry in an incognito window with extensions disabled.

data-channel-failed: message did not round-trip

The peers connected, but the test message did not echo back. Rare, usually a browser bug or extension interference with data channels. Update the browser to the latest version, disable extensions, and retry.

connection-failed: negotiation could not complete

A general local negotiation failure not covered by the cases above. Open the browser console for the specific error and retry.

Warnings: getdisplaymedia-limited and codec-poor

Two conditions show as a yellow Warn rather than a fail, because the call still connects:

For IT admins

WebRTC needs outbound UDP. Signaling reaches a STUN server on UDP 3478 (Google also uses 19302), the browser learns its public mapping, and media then flows over ephemeral UDP ports. Anything that blocks that UDP breaks calls while leaving web pages working perfectly, which is why "the internet is fine but meetings fail" is such a common ticket.

The signal that matters. An only-host result, with the local network discovered but no srflx, means outbound UDP to STUN is being dropped. Allow outbound UDP egress to the STUN ports, or stand up a TURN relay with a TCP/TLS-443 fallback for networks that refuse UDP as policy. A TURN relay is what production conferencing apps rely on for the strictest networks.

Browser-level blocks. A no-candidates result is local, not network. On managed Chrome and Edge, review WebRTC-related enterprise policies (for example WebRtcUdpPortRange and any policy that disables WebRTC). Privacy extensions and hardened browser builds disable it too. Test a known-good machine on the same network to separate a policy problem from a firewall problem.

mDNS candidates. Modern Chrome and Firefox hide local IPs behind .local mDNS candidates by default. That is expected and does not break connectivity. Where an internal application legitimately needs the real local IP, Chrome's WebRtcLocalIpsAllowedUrls policy can reveal it for specific origins.

Split-tunnel VPN. If calls work off-VPN but fail on it, the VPN is likely routing media differently from signaling or dropping UDP. Check the split-tunnel rules and the VPN's UDP policy.

Native vs browser. Teams and Zoom desktop apps use their own media stacks and port ranges; this tool measures browser WebRTC (Meet, Teams web, Slack Huddles, Zoom web). The firewall UDP rules usually overlap, so a STUN-blocked result is a strong predictor of trouble for the native apps as well.

Behind the scenes

STUN runs over UDP, and UDP emitted by RTCPeerConnection is not governed by the page's Content-Security-Policy connect-src (CSP governs fetch, XHR, and WebSocket, not the raw UDP WebRTC uses). That is why this tool can reach STUN even though the page's CSP lists no external hosts. The four STUN servers are named in the source (app.js) so anyone can see exactly which servers are contacted: Google, Cloudflare, and Mozilla.

The end-to-end step needs no signaling server because both peers live in the same page; the offer, answer, and ICE candidates are handed between them directly in JavaScript. This isolates the local WebRTC stack from any network dependency, so step 3 failing while step 2 passed points at the browser, not the firewall.

Passing step 2 requires a host candidate and a srflx candidate. Host alone proves the stack works locally; srflx proves a packet reached a public STUN server and its reply came back, which is the real-world requirement for a call to connect through NAT.

Your public IP is shown once at the top of step 2; the per-candidate list redacts public addresses so a screenshot does not leak them. The test carries no TURN server, so on a symmetric-NAT or UDP-blocked network the honest result is only-host, and a real deployment would supply its own TURN relay.

Apart from the STUN UDP probes to the four listed servers, nothing leaves the tab: getUserMedia is only feature-detected and never called, there is no telemetry or analytics, and the in-page negotiation is entirely local. Open DevTools, Network tab, to confirm no HTTP requests fire during the run.