What Is WebRTC?
When a browser connects directly to another browser without routing audio or video through a server, it is using WebRTC. Standardized by the W3C and IETF, WebRTC (Web Real-Time Communication) provides APIs for peer-to-peer audio, video, and arbitrary data exchange using JavaScript in the browser. Chrome, Firefox, Safari, and Edge all implement WebRTC natively, enabling video calling, file sharing, and multiplayer gaming without installing plugins or native applications.
What is WebRTC?
How WebRTC establishes a peer connection
Establishing a WebRTC connection requires a signaling step that WebRTC itself does not define. The peers must exchange SDP blobs describing their capabilities and ICE candidates through some out-of-band channel. This tool uses manual copy-paste for the SDP exchange; production applications use WebSocket servers, HTTP endpoints, or messaging systems. Once both peers have exchanged SDP, the ICE agent attempts to connect using the candidate addresses discovered by STUN. Consequently, WebRTC requires at minimum a STUN server for NAT traversal and a signaling mechanism, even though the media and data channels are truly peer-to-peer. The signaling step is often the most confusing part of WebRTC development because the standard deliberately leaves it unspecified, leaving each application to choose the transport that best fits its deployment constraints and existing infrastructure.
CapyToolkit uses manual SDP copy-paste as its signaling mechanism, which makes the entire connection process visible and debuggable without needing a dedicated signaling server or third-party service. The SDP blob contains codec candidates, ICE candidate addresses, and DTLS fingerprint information, all of which are visible in the text area before you paste them to the remote peer.
WebRTC data channels versus media tracks
WebRTC supports two distinct transport types: media tracks and data channels. Media tracks carry audio and video streams using the SRTP/RTP protocol with built-in codec negotiation, echo cancellation, and bandwidth adaptation. Data channels use SCTP over DTLS1, providing a message-based transport for arbitrary binary or text data with configurable reliability (ordered/unordered) and delivery guarantee (reliable/unreliable). Yet despite sharing the same ICE and DTLS layer, data channels and media tracks are negotiated independently in the SDP. This tool uses a data channel exclusively (no audio or video) to measure pure network metrics without codec overhead. The data channel's configurable reliability settings let you choose between reliable ordered delivery (similar to TCP) and unreliable unordered delivery (similar to UDP), which is the same trade-off that real-time applications face when configuring their own WebRTC data channels for game state, file transfer, or messaging use cases.
Security model in WebRTC
All WebRTC media and data is encrypted end-to-end. Media tracks use SRTP (Secure Real-Time Transport Protocol); data channels use DTLS (Datagram Transport Layer Security) with SCTP. The DTLS handshake uses certificate fingerprints exchanged in the SDP; if a man-in-the-middle modifies the SDP, the fingerprint mismatch causes the DTLS handshake to fail. Furthermore, browsers require WebRTC to run on pages served over HTTPS2, preventing the API from being accessed on insecure origins. TURN relay servers see only encrypted packets and cannot inspect media or data content. CapyToolkit runs entirely in the browser and does not transmit your SDP or media content to any server, so the security model of the test itself is consistent with WebRTC's end-to-end encryption design: your data stays on your device throughout the entire session.
The three core WebRTC JavaScript APIs
Three browser APIs form the entire WebRTC surface available to web applications. getUserMedia() requests access to the device's camera and microphone, returning a MediaStream for attachment to a peer connection as a media track. RTCPeerConnection manages the ICE negotiation, DTLS handshake, SRTP key exchange, and data transport. RTCDataChannel is created from an existing RTCPeerConnection and provides bidirectional message passing for arbitrary data without involving media tracks.
This tool uses only RTCPeerConnection and RTCDataChannel; it requests no microphone or camera permissions. The data channel carries probe packets between the two browser instances, measuring round-trip time, jitter, and packet loss over the ICE-selected path. Understanding which API handles which function makes it easier to diagnose whether a WebRTC problem originates in the media acquisition layer, the connection negotiation layer, or the data transport layer.
Browser API compatibility across major browsers
RTCPeerConnection is supported in Chrome 23+, Firefox 22+, Safari 11+, and Edge 79+3. RTCDataChannel reached cross-browser parity in late 2021 with Safari's adoption of the SCTP data channel specification, which resolved the earlier inconsistency where Safari was the last major browser to implement the data channel API. getUserMedia() requires HTTPS or localhost; browsers block camera and microphone access on insecure HTTP origins as a security policy. The WebRTC API surface is now stable across all major browsers, with minor differences in optional features such as RTCRtpSender.setParameters() behavior and statistics API field availability that do not affect the core functionality this tool relies on for P2P connectivity testing.
WebRTC codec negotiation and browser codec support
Browser codec selection for WebRTC follows the SDP offer/answer exchange. The offering browser lists all its supported codecs in the SDP offer; the answering browser selects the codecs it also supports from that offered list. For video, Chrome and Firefox support VP8, VP9, and H.264 (AVC); Safari adds H.265 (HEVC) support on Apple hardware when a hardware encoder is available. Opus is the mandatory audio codec for WebRTC per RFC 78744; G.711 (PCMA/PCMU) remains widely supported for compatibility with SIP and PSTN gateways.
Codec selection affects connection quality measurably. VP9 produces better video quality per bit than VP8 at the same bitrate, making it preferable for bandwidth-constrained connections. H.264 with hardware encoding reduces CPU load on mobile devices where software encoding causes thermal throttling. Your application can influence codec priority by reordering codec payload types in the SDP offer before calling setLocalDescription(), which causes the answering peer to select your preferred codec if it supports it.
Selecting codecs with RTCRtpSender.setParameters()
Chrome and Firefox support codec preference selection via RTCRtpSender.setParameters() or by reordering the SDP offer's codec payload type list before the offer is sent. Setting a specific codec as the first entry in the codecs array of the sender's parameters tells the answering peer to prefer it if supported. This is the standard approach for forcing VP9 or H.265 when the default codec selected during negotiation is not optimal for your use case.
Server-assisted WebRTC: SFUs, MCUs, and media servers
Direct peer-to-peer WebRTC works well for two participants, but group calls with more than two peers require a server-side component. Selective Forwarding Units (SFUs) receive each participant's media stream and forward it to all other participants without mixing or transcoding. Each participant sends one stream to the SFU and receives one stream per other participant from it, scaling to dozens of participants with low server CPU because the SFU forwards packets rather than decoding and re-encoding them.
MCU (Multipoint Control Unit) architectures mix all participants' streams into a single composite output on the server, sending each participant one combined stream regardless of participant count. MCUs require more server CPU but reduce each client's incoming bandwidth to one stream. SFUs are the preferred architecture for modern WebRTC applications; mediasoup, Janus, and Jitsi Videobridge are widely deployed open-source SFU implementations that run on standard Linux server hardware.
How SFU routing differs from TURN relay
SFU routing and TURN relay are architecturally distinct. TURN relay is an ICE fallback for NAT traversal: it relays encrypted packets between two direct peers when hole-punching fails. SFU routing is a deliberate media architecture where the server participates in the media flow, receiving streams from each client and forwarding them selectively to others. A WebRTC connection through an SFU still uses ICE and DTLS between each client and the SFU server; the SFU is a topology choice, not a NAT traversal mechanism.
Understanding the distinction prevents confusing a media-server deployment with a NAT-traversal workaround when you read a connection architecture description. An SFU scales a group call by forwarding streams, whereas TURN only appears when two peers cannot reach each other directly through their NAT devices. Both can show up in the same system, so the presence of relay candidates still signals a traversal problem even when an SFU is handling the media distribution for a multi-participant room.
Try in the tool
What this page covers
- getUserMedia() requests camera/microphone access, returning a MediaStream
- RTCPeerConnection manages ICE negotiation, the DTLS handshake, and SRTP key exchange
- RTCDataChannel bidirectional message transport over SCTP/DTLS, independent of any media track
- Browser support baseline RTCPeerConnection: Chrome 23+, Firefox 22+, Safari 11+, Edge 79+
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
R. Jesup et al., "WebRTC Data Channels," RFC 8831, IETF, January 2021. https://www.rfc-editor.org/rfc/rfc8831.html
- 2.
Mozilla Developer Network, "MediaDevices: getUserMedia() method," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
- 3.
Mozilla Developer Network, "RTCPeerConnection," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection
- 4.
J. Valin and C. Bran, "WebRTC Audio Codec and Processing Requirements," RFC 7874, IETF, May 2016. https://www.rfc-editor.org/rfc/rfc7874.html
CapyToolkit uses manual SDP copy-paste as its signaling mechanism, which eliminates the need for a signaling server entirely for testing purposes. WebRTC requires a signaling mechanism to exchange SDP, which typically involves a server. However, the media and data after connection is peer-to-peer. A STUN server is needed for NAT traversal. TURN relay servers are needed when direct connection fails. None of these servers handle application media content.
Chrome, Firefox, Safari (since version 11), Edge, Opera, and most mobile browsers on iOS and Android support WebRTC. Feature parity varies; data channel reliability options and unified plan SDP semantics differ between older implementations.
No. WebSockets are a persistent full-duplex TCP connection between a browser and a server. WebRTC is a peer-to-peer protocol for browser-to-browser communication using UDP-based transport. WebSockets are often used as the signaling channel to exchange SDP for a WebRTC connection, but they serve different purposes.
Yes. WebRTC data channels support binary data transfer with configurable reliability and ordering. Large files are split into chunks and sent over the data channel. Without TURN relay, the transfer is peer-to-peer with no server storage. Transfer speed is limited by the slower of the two peers' upload and download bandwidth.
Yes, always. DTLS-SRTP is mandatory for all WebRTC connections with no opt-out. The browser's WebRTC implementation enforces this; JavaScript code cannot disable encryption. This encryption applies to both media tracks and data channels.
What Is NAT (Network Address Translation)?
Because home networks share a single public IP address among many devices, every router performs NAT. Network Address Translation maintains a mapping table that tracks outbound connections from internal IP:port pairs to external IP:port pairs on the router's WAN interface.1 When a response arrives, the router consults this table and forwards the packet to the correct internal device. This mechanism allows a household with 10 devices to share one IP address assigned by the ISP.
What is NAT?
RFC 1918 addresses (192.168.x.x, 10.x.x.x, 172.16.x.x) to a single public routable IP address,2 enabling outbound internet access while blocking unsolicited inbound connections. The NAT translation table tracks active connections so the router can route return packets to the correct internal device.NAT types and their effect on P2P connectivity
Full Cone NAT (Open) accepts any inbound packet on a mapped port from any source. Restricted Cone NAT accepts inbound packets only from IP addresses the internal host contacted first. Port Restricted Cone adds the source port check on top of the IP check. Symmetric NAT, the strictest type, assigns a different external port for each unique destination IP:port and is the one that breaks WebRTC direct connections.3 Consequently, the NAT type of both peers determines whether ICE hole-punching succeeds or falls back to TURN relay routing.
How STUN classifies NAT behavior
STUN servers identify NAT type by probing from multiple source addresses and comparing the mapped external address and port the server observes against the internal address and port of the client. When the same internal port maps to the same external port regardless of destination, the NAT is cone-based; when the external port changes per destination, the NAT is symmetric. CapyToolkit performs the same multi-server STUN comparison that production WebRTC applications use to classify NAT behavior, so the result you see here matches what your video call or gaming application experiences when it evaluates whether a direct connection is viable.
Carrier-grade NAT and its limitations
Carrier-grade NAT (CGNAT) applies a second layer of NAT at the ISP level, above your home router's NAT. ISPs deploy CGNAT to conserve public IPv4 addresses by sharing one public IP among hundreds of customers. Building on the home router NAT, CGNAT adds a second translation layer that typically uses symmetric port assignment, making direct P2P connections impossible for affected users. Addresses in the 100.64.0.0/10 range (Shared Address Space) indicate CGNAT is active.4 The only reliable fix is requesting a dedicated public IP from the ISP; many ISPs offer this as an optional paid service. CapyToolkit's STUN probe reveals whether your ISP has placed you behind CGNAT by checking whether the discovered public IP falls in the shared address range, which is a strong signal that you should contact your ISP before attempting any router-side configuration changes.
IPv6 and the future of NAT
IPv6 provides enough address space for every device on earth to have a unique globally routable address, eliminating the need for NAT entirely.5 IPv6 connections bypass the NAT traversal problems that affect IPv4 WebRTC connections; ICE generates host candidates directly from the device's global IPv6 address, enabling direct connections without STUN or TURN involvement. Yet IPv6 deployment is incomplete across residential ISPs and mobile networks, meaning NAT traversal will remain relevant for the foreseeable future. Enabling IPv6 on your router and ISP connection is the most direct long-term solution to NAT-related WebRTC connectivity issues. CapyToolkit's STUN probe returns both IPv4 and IPv6 addresses when available, so you can determine whether your connection has a globally routable IPv6 address that would allow direct peer-to-peer connectivity without any NAT traversal overhead.
Port forwarding and DMZ mode as static workarounds for restrictive NAT
Port forwarding creates a permanent NAT table entry that routes all inbound traffic on a specific external port to a designated internal IP and port, regardless of whether the internal device initiated any outbound connection. This bypasses the inbound-connection restriction of restricted cone and port-restricted cone NAT for the specific application ports configured. Game consoles and self-hosted services benefit most because they require predictable inbound connectivity on well-known ports.
DMZ mode (Demilitarized Zone) takes port forwarding further by routing all inbound traffic on all external ports to a single designated internal device. The device in DMZ receives all unsolicited inbound connections, replicating the behavior of a device with a direct public IP. Consequently, DMZ provides the equivalent of Full Cone NAT for the designated device; most home routers limit DMZ to one internal device at a time.
Security implications of port forwarding and DMZ
Both port forwarding and DMZ increase the attack surface for the designated device. Port forwarding exposes only the forwarded ports to the public internet; a service with port 80 forwarded accepts connections from any external source on that port. DMZ exposes all ports, making the device fully reachable from the internet. Running a software firewall on the DMZ device and keeping its software current is essential, because no router-level filtering stands between the device and inbound connections from the public internet.
NAT interaction with VPN tunnels and split tunneling
Routing traffic through a VPN changes the NAT characteristics visible to external peers. When a VPN client runs on the router, all LAN traffic exits through the VPN tunnel, and the VPN server's public IP becomes the externally visible address. The NAT type the STUN probe observes depends on the VPN server's NAT configuration, not the home router's, because the outbound packets arrive at the internet from the VPN server's address rather than the home router's WAN IP.
Split tunneling routes only specific traffic through the VPN while leaving other traffic on the direct ISP path. With split tunneling active, WebRTC traffic configured to bypass the VPN uses the ISP path and the home router's NAT. Running the STUN probe while WebRTC bypasses the VPN shows the ISP-path NAT type; enabling VPN for all traffic and retesting shows the VPN-path NAT type for direct comparison.
WireGuard interface NAT and WebRTC connectivity
WireGuard creates a network interface on the operating system. Traffic routed through this interface exits from the WireGuard peer endpoint's address. If the peer endpoint is a VPS with a direct public IP, WebRTC ICE generates reflexive candidates from the VPS's public IP, and hole-punching succeeds as if you had a direct public IP yourself. This makes WireGuard a practical NAT traversal solution for users behind CGNAT who can operate a small VPS as a WireGuard endpoint, converting symmetric CGNAT into an effectively open direct-IP configuration for WebRTC traffic.
The WireGuard approach trades a small monthly VPS cost for a stable public endpoint that survives the CGNAT layer your ISP controls. Unlike requesting a dedicated IPv4 from the provider, this method works even when the ISP refuses to assign a public address to residential customers. Because the tunnel exit carries a real routable IP, the ICE agent gathers reflexive candidates from that address and hole-punching succeeds exactly as it would for any user with native direct connectivity.
Try in the tool
What this page covers
- RFC 1918 private ranges 192.168.x.x, 10.x.x.x, and 172.16.x.x, all translated to one public IP
- Port forwarding a permanent NAT table entry routing a specific external port to one internal device
- DMZ mode routes all inbound traffic on all ports to a single device, most routers allow only one at a time
- IPv6 as the long-term fix gives every device a globally routable address, removing NAT traversal entirely
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
Wikipedia, "Network address translation," en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/Network_address_translation
- 2.
Y. Rekhter et al., "Address Allocation for Private Internets," RFC 1918, IETF, February 1996. https://www.rfc-editor.org/rfc/rfc1918.html
- 3.
J. Rosenberg et al., "STUN - Simple Traversal of User Datagram Protocol (UDP) Through Network Address Translators (NATs)," RFC 3489, IETF, March 2003. https://www.rfc-editor.org/rfc/rfc3489.html
- 4.
Wikipedia, "Carrier-grade NAT," en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/Carrier-grade_NAT
- 5.
IANA, "IPv6 Addressing Architecture," iana.org, accessed June 2026. https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml
CapyToolkit's STUN probe reveals the NAT type your router applies, which is independent of the firewall configuration on the same device. NAT translates IP addresses and port numbers to route packets between private and public networks. A firewall filters packets based on rules about which connections to allow or block. Home routers combine both functions; NAT handles address translation while the firewall blocks unsolicited inbound connections. Disabling one does not disable the other.
For IPv4, bypassing NAT requires a dedicated public IP routed directly to your device, either through your ISP or a VPN with split tunneling. For IPv6 with a supporting ISP, devices get globally routable addresses without any NAT. DMZ mode on a home router places one device directly on the public WAN IP, effectively removing NAT for that device.
NAT itself has negligible performance overhead on modern router hardware. The translation table lookup adds microseconds per packet. What does affect speed is the router's overall throughput capacity and the ISP link. NAT translation is not a bottleneck on residential connections.
Both gaming P2P and WebRTC use ICE hole-punching, which requires that the router accept incoming packets on the same port used for the outbound STUN request. Symmetric NAT assigns different ports per destination, so the incoming packet from the peer arrives on a port the router never created a mapping for and drops it.
UPnP (Universal Plug and Play) is a protocol that lets devices request port mappings from the router automatically. A game console or WebRTC application using UPnP can ask the router to open a specific port for incoming connections, effectively working around restricted cone NAT without manual port forwarding.
What Is Network Jitter?
When packets arrive at irregular intervals instead of steady ones, the application experiencing them encounters jitter. Network jitter is the statistical variation in packet arrival timing, measured as the standard deviation of inter-packet arrival intervals or, for real-time media applications, as the RFC 3550 exponential weighted mean deviation.1 Even when average latency is acceptable, high jitter forces adaptive buffers to grow larger to absorb the timing variation, adding fixed delay on top of the measured average.
What is network jitter?
RFC 3550 defines jitter for RTP (real-time media) as the mean deviation of the difference in packet spacing between sender and receiver, updated continuously using an exponential weighted average that weights recent measurements more than older ones.Why jitter damages real-time applications
Voice and video applications assume regular packet delivery. A codec that generates an audio frame every 20 ms expects to receive frames every 20 ms at the other end. When jitter causes frames to arrive every 5 ms, then 40 ms, then 12 ms, the playout buffer must hold frames until the late-arriving ones catch up, adding the maximum delay variation as a fixed buffer latency. Consequently, 30 ms of jitter adds at least 30 ms of buffer delay to every call, independent of average RTT. File transfers and web browsing tolerate jitter transparently because TCP retransmission handles out-of-order delivery without requiring fixed timing.
What causes jitter on home connections
Router queue management is the primary jitter source on home networks. When a burst of traffic arrives at the router, the outbound queue fills briefly, adding queuing delay to packets that arrive during the burst. Once the burst clears, queuing delay drops, causing the variation. Wi-Fi retransmissions are a second source: when a wireless frame fails to transmit on the first attempt, the 802.11 backoff mechanism retries after a delay, adding an irregular additional delay to that frame.2 Building on these sources, competing downloads on the same LAN cause intermittent queue bursts; a single device starting a large download spikes jitter for all concurrent real-time streams.
How competing LAN traffic amplifies jitter
When a single device on the home LAN starts a large TCP download, the outbound queue at the router fills with acknowledgment packets and data segments that compete for the same WAN uplink. Real-time UDP packets from a video call or VoIP session share that queue, so their queuing delay varies with the burst pattern of the competing TCP flow. The jitter spike lasts for the duration of each TCP burst, producing the characteristic jitter signature of bufferbloat: low baseline jitter punctuated by short spikes that coincide with bulk data transfers. Disconnecting the competing device or enabling QoS to prioritize UDP real-time traffic eliminates the competing-traffic jitter source without requiring any change to the physical network.
The effect is most pronounced when the competing traffic is bidirectional, such as a cloud backup or peer-to-peer sync running in both directions. Upstream acknowledgment packets and downstream data segments both contend for the same narrow WAN queue, doubling the burst frequency and widening the jitter distribution. A VoIP call sharing this path will exhibit a jitter signature that correlates directly with the backup's upload bursts, visible in the sparkline as periodic spikes repeating at the backup's interval.
Reducing jitter at the network level
Quality of Service (QoS) settings that prioritize UDP traffic from real-time applications prevent competing TCP downloads from filling the outbound queue, reducing queuing jitter from 20 to 40 ms down to 2 to 5 ms for prioritized traffic. Active Queue Management (AQM) algorithms like CAKE or FQ-CoDel, available on OpenWrt-based routers, apply intelligent queue management that keeps queuing delay low even under load.2 Furthermore, switching from 2.4 GHz Wi-Fi to 5 GHz or wired Ethernet eliminates wireless retransmission jitter entirely for connections where radio reliability is the dominant jitter source. CapyToolkit's jitter tester reports the same jitter statistic that VoIP codecs use internally, so the reduction you see after enabling QoS or switching to a better radio band is the same improvement your call application would report from its own jitter buffer measurements.
Measuring jitter with the WebRTC Statistics API
The WebRTC Statistics API exposes live jitter measurements from active RTCPeerConnection sessions. Calling RTCPeerConnection.getStats() returns a collection of statistics objects; the RTCInboundRtpStreamStats object for each incoming media track includes a jitter field measured in seconds,3 calculated using the RFC 3550 exponential weighted mean deviation formula. For data channels, comparing consecutive RTCIceCandidatePairStats.currentRoundTripTime samples provides an equivalent jitter measurement derived from per-probe timing variation.
Accessing these statistics without modifying application code is possible through Chrome's chrome://webrtc-internals diagnostic page or Firefox's about:webrtc page. Both display live statistics for all active RTCPeerConnection sessions including incoming jitter, outgoing jitter, packet loss, and round-trip time. Opening either page before starting a call captures the full jitter trend across the session without any instrumentation changes to the application code.
Polling getStats() for jitter trend analysis
Polling getStats() at 1 to 2 second intervals and comparing successive jitter field values reveals trends over time. A stable value that suddenly spikes indicates a transient network event; a value that gradually increases over minutes indicates growing congestion on the ISP path. The RFC 3550 jitter calculation weights recent samples more than older ones, so the reported value tracks recent conditions rather than an all-session average. This responsiveness makes it more useful for real-time troubleshooting than a raw standard deviation over a fixed window.
Adaptive jitter buffers in WebRTC applications
WebRTC browsers implement an adaptive jitter buffer to handle incoming audio and video streams with timing variation. The buffer holds incoming packets temporarily before playing them out at the expected rate, absorbing arrival variation by adding a fixed delay equal to the current jitter level. Chrome's audio jitter buffer uses the NetEQ algorithm,4 which adjusts buffer size dynamically: the buffer grows when jitter increases and shrinks when jitter stabilizes, keeping added latency proportional to actual variation observed.
Buffer underruns occur when a packet arrives later than the buffer expected, producing a playout gap that the codec's packet concealment algorithm fills with synthetic audio. Buffer overflows occur when packets arrive faster than expected, causing the buffer to grow or discard frames to manage latency. Neither condition appears as an explicit error; both manifest as audio artifacts or reduced video quality visible only through subjective quality assessment.
Why jitter buffer size adds directly to perceived call latency
Jitter buffer size adds to end-to-end call latency proportionally. A buffer configured for 40 ms of jitter absorbs timing variation by holding packets for up to 40 ms before playing them out, adding that 40 ms to every packet's effective latency regardless of the underlying network RTT. Consequently, a connection with 30 ms average RTT and 35 ms of jitter produces approximately 75 ms of perceived one-way delay: 15 ms propagation plus 40 ms buffer. Reducing network jitter through QoS or wired Ethernet directly reduces the buffer size the codec requires, lowering perceived call latency without changing the physical network path.
Try in the tool
What to look for
- Excellent jitter 5 ms
- Buffer needed at excellent jitter 5 to 10 ms
- Jitter needing larger buffers above 20 ms
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
H. Schulzrinne et al., "RTP: A Transport Protocol for Real-Time Applications," RFC 3550, IETF, July 2003. https://www.rfc-editor.org/rfc/rfc3550.html
- 2.
Bufferbloat Project, "Bufferbloat FAQs," bufferbloat.net, accessed June 2026. https://www.bufferbloat.net/projects/bloat/wiki/Bufferbloat_FAQs/
- 3.
Mozilla Developer Network, "RTCInboundRtpStreamStats: jitter property," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/RTCInboundRtpStreamStats/jitter
- 4.
Chromium WebRTC, "NetEq," chromium.googlesource.com, accessed June 2026. https://chromium.googlesource.com/external/webrtc/+/master/modules/audio_coding/neteq/g3doc/index.md
CapyToolkit measures jitter using the same RFC 3550 formula that VoIP codecs use, so the number you see matches what your call application experiences internally. Latency is the average time for a packet to travel from sender to receiver. Jitter is the variation in that time from packet to packet. High latency delays all packets equally and consistently. High jitter means packets arrive at unpredictable intervals, disrupting time-sensitive applications even when the average latency is acceptable.
A jitter buffer is a queue at the receiver that holds incoming packets temporarily before playing them out at a fixed rate. By absorbing the timing variation before playback, the buffer eliminates audible jitter at the cost of adding its buffer size as fixed latency. Adaptive jitter buffers grow and shrink in response to measured jitter to balance latency against smoothness.
Yes, 5 ms jitter is excellent. Most adaptive jitter buffers handle 5 ms variation with a buffer of 5 to 10 ms, adding negligible latency. The audio will be smooth and natural at this jitter level. Jitter above 20 ms starts to require larger buffers and produces noticeable delay in echo feedback.
QoS reduces queuing jitter on the local network by preventing low-priority traffic from filling the queue. It cannot reduce jitter originating on ISP backbone links or at peering points outside the home network. Well-implemented QoS typically reduces local jitter from 20 to 40 ms down to 2 to 5 ms for prioritized traffic.
The download fills the outbound upload queue if it includes acknowledgment packets, and can fill the download queue if bandwidth is fully saturated. Queue buildup introduces variable queuing delay for packets sharing the same queue, including real-time media packets. QoS priority for real-time UDP prevents the download from filling the real-time queue.
What Is Packet Loss?
Although networks transmit packets reliably most of the time, a percentage of packets fail to reach their destination in every real network. Packet loss is the ratio of lost packets to total transmitted packets, expressed as a percentage. At 0%, every packet arrives. At 1%, roughly one packet in every hundred is dropped somewhere along the path.1 Real-time applications including voice calls, video conferencing, and multiplayer games are especially sensitive to loss because missing data cannot be retransmitted fast enough to be useful.
What is packet loss?
What causes packet loss
Link saturation is the most common cause of packet loss on residential connections. When an outbound link is fully utilized (upload saturated by a file upload, or download saturated by a streaming service), the router drops incoming packets because no buffer space remains. Wireless interference causes a different type of loss: the 802.11 protocol retransmits failed frames, but at the UDP application layer, the excessive retransmission delay eventually causes application-level timeouts that count as loss. Hardware failures in routers, switches, or network cards produce random loss that is not correlated with traffic volume. Consequently, distinguishing time-correlated loss from random loss identifies the root cause.3
How real-time applications handle packet loss
VoIP and video codecs use packet concealment to bridge gaps caused by loss. When a packet does not arrive in time, the codec generates synthetic audio or freezes the video frame for the duration of the gap. This concealment sounds natural at 1 to 2% loss. At 3 to 5%, the concealment gaps become audible and visible. Above 5%, the application may fall back to a lower-quality codec, reduce frame rate, or show a "connection unstable" indicator.
How Forward Error Correction changes the loss tolerance threshold
Building on this, Forward Error Correction (FEC) codecs transmit redundant data alongside primary packets, allowing receivers to reconstruct lost packets from the redundant data at the cost of increased bandwidth. CapyToolkit sends UDP probes that are treated the same way as VoIP RTP packets by the network, so the loss figure you see reflects what your voice codec would experience on the same path.
The trade-off with FEC is bandwidth overhead: a typical FEC scheme might add 20 to 50% more packets to the stream, which can itself contribute to queue saturation on congested links. Applications that implement adaptive FEC dynamically adjust the redundancy ratio based on measured loss, increasing FEC when loss spikes and reducing it when the path is clean, to balance the overhead against the protection gained. This adaptive approach is what allows modern WebRTC implementations to maintain call quality on lossy Wi-Fi without permanently doubling the bitrate.
Distinguishing random from burst packet loss
Random loss distributes drops evenly across all packets with no temporal pattern. Burst loss clusters multiple consecutive drops together, then drops zero packets for a period. Burst loss is more damaging to real-time applications because codec concealment handles single isolated losses well but fails when two or three consecutive packets are missing. The sparkline in this tool helps identify burst loss; a cluster of red markers in a short window indicates burst loss, while scattered individual markers indicate random loss. Yet the average loss percentage looks the same in both cases, so visual inspection of the sparkline provides diagnostic information the percentage alone cannot.
Bufferbloat: how oversized queues create burst loss under load
Bufferbloat occurs when a router's transmit queue grows larger than the network can drain quickly, causing packets to wait hundreds of milliseconds before transmission. The queue does not drop packets while filling (no loss occurs during the fill phase), but when the queue reaches its capacity limit it drops all subsequently arriving packets until it empties. This sudden drop event looks identical to physical link failure in short-duration tests: 100% loss for a brief window, then recovery when the queue drains. The signature distinguishing bufferbloat loss from true path loss is a simultaneous RTT spike; bufferbloat loss always coincides with dramatically elevated latency visible in the sparkline.
For UDP-based real-time applications, bufferbloat loss is often more damaging than the measured percentage suggests. A queue taking 500 ms to drain means every packet in that queue arrives 500 ms late; for VoIP or gaming with 100 ms jitter buffer limits, these late packets are discarded alongside the dropped ones, amplifying the effective loss rate beyond what the raw counter shows.
How Active Queue Management prevents bufferbloat-induced loss
AQM algorithms (CAKE, fq_codel, PIE) limit queue depth by dropping packets early to signal TCP senders to reduce their rate. Because they drop predictably to control depth rather than reactively when the buffer overflows, they eliminate the burst loss pattern associated with overflow. With CAKE enabled on the router, packet loss during a large file download stays near 0% because queue depth remains bounded. Without AQM, the same download can produce 5 to 15% burst loss on concurrent UDP streams when TCP monopolizes the transmit queue.4
Why TCP traffic hides loss that UDP applications expose
TCP retransmits lost packets automatically using the operating system's network stack. When a packet is dropped in transit, TCP detects the gap via sequence number tracking and retransmits the missing segment within one to two round-trip times.2 The application layer receives complete, ordered data regardless of how many retransmissions occurred. File downloads, web browsing, and API calls all complete correctly on a connection with 5% packet loss; the only visible effects are reduced throughput and increased latency from retransmission overhead.
UDP applications receive no such protection. A UDP packet that does not arrive is simply absent; the receiving application detects the gap from its own sequence numbering and applies concealment or error correction at the application layer. For VoIP codecs and game state updates, a retransmitted packet arriving one RTT later is no longer useful because the conversation has moved on and the game state has advanced, so the drop produces a gap in audio or a missed game update rather than a mere delay.
Practical implications for network troubleshooting
A network with 3% packet loss that causes no visible problems during web browsing or file downloads will reveal its loss rate immediately when VoIP or gaming starts. TCP's retransmission mechanism masks the loss from most casual testing. Running a UDP-based loss test like this tool on any connection with unexplained VoIP quality problems reveals the loss rate that browser-based speed tests and download throughput measurements cannot expose.
Try in the tool
What to look for
- Barely noticeable loss 1%
- Audible dropout 3%
- Noticeably poor quality 5%
- Difficult conversation 10%
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
Wikipedia, "Packet loss," en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/Packet_loss
- 2.
Y. Cheng et al., "The RACK-TLP Loss Detection Algorithm for TCP," RFC 8985, IETF, February 2021. https://www.rfc-editor.org/rfc/rfc8985.html
- 3.
Wikipedia, "Tail drop," en.wikipedia.org, accessed June 2026. https://en.wikipedia.org/wiki/Tail_drop
- 4.
Bufferbloat Project, "Bufferbloat FAQs," bufferbloat.net, accessed June 2026. https://www.bufferbloat.net/projects/bloat/wiki/Bufferbloat_FAQs/
1% loss produces occasional brief gaps that most listeners attribute to the speaker pausing. At 3%, gaps are audible and callers may ask for repetition. At 5%, the call quality is noticeably poor. At 10%, conversation becomes difficult. CapyToolkit sends UDP probes that are treated the same way as VoIP RTP packets by the network. Most VoIP applications display a quality warning above 3%, so the loss figure you see reflects what your voice codec would experience on the same path.
TCP detects lost packets via sequence numbers and retransmits them automatically. The application layer receives complete, ordered data regardless of loss. However, retransmission adds latency, which is why TCP is unsuitable for real-time audio and video where a late packet is worse than no packet.
Most ISP speed tests focus on throughput rather than packet loss. They use TCP, which hides loss through retransmission. Tests using UDP probes, like this tool, reveal actual UDP packet loss. A speed test may show full bandwidth while this tool shows 2% loss on the same connection.
Not always. On shared ISP infrastructure, packet loss typically ranges from 0% to 0.1% during off-peak hours. During peak evening hours, loss can reach 0.5 to 2% on congested residential connections. 0% loss is achievable on a lightly loaded wired connection but is not guaranteed on any shared network segment.
Loss means a packet never arrives. Reordering means a packet arrives later than expected, out of sequence. TCP handles both through its sequencing and retransmission system. UDP applications must handle reordering themselves; RTP uses sequence numbers to detect and reorder out-of-sequence packets. High reordering looks similar to high jitter from the application's perspective.
What Is ICE (Interactive Connectivity Establishment)?
Before two peers can exchange data directly, they must discover which network paths between them actually work. ICE (Interactive Connectivity Establishment) is the IETF protocol defined in RFC 8445 that handles this discovery automatically.1 ICE gathers candidate addresses (local IPs, STUN-discovered public IPs, and TURN relay addresses), exchanges them through signaling, then performs connectivity checks on every candidate pair to find the one with the highest priority that successfully passes data in both directions.
What is ICE?
ICE candidate gathering and exchange
ICE gathering collects three types of candidates. Host candidates are the device's local network interfaces (LAN IP addresses assigned by DHCP). Server-reflexive candidates are discovered by sending STUN binding requests to STUN servers, which return the public IP:port the NAT router assigned. Relay candidates are obtained from TURN servers, which allocate a relay address on the server's public IP. All candidates are encoded in SDP and exchanged with the remote peer through the signaling channel.2 Consequently, each peer sends its candidates to the other, and the ICE agent builds a candidate pair list from all combinations of local and remote candidates. CapyToolkit performs the same gathering sequence as any WebRTC application, so the candidate types displayed here match exactly what your video call or gaming application would negotiate when establishing a peer connection.
Connectivity checks and candidate pair selection
With candidate pairs formed, ICE begins connectivity checks: sending STUN binding requests to each remote candidate from each local candidate. A successful check means the STUN request arrived at the remote peer and the response reached back, confirming bidirectional connectivity. ICE prioritizes candidate pairs by type (host over srflx over relay) and network cost. Building on this, the first successful check on a high-priority pair nominates it as the active connection. During the checking phase, ICE sends multiple STUN requests per candidate pair over several hundred milliseconds to account for packet loss on the path, so a single failed request does not eliminate a candidate pair from consideration.
How ICE restarts handle network changes mid-session
ICE can switch active pairs if the nominated pair later fails; this ICE restart mechanism enables seamless network handoff when a device switches from Wi-Fi to mobile data.3 The priority ordering explains why you may see different ICE candidate types at different times on the same network: when a host candidate succeeds, ICE uses it; when the host path breaks, ICE falls back to srflx or relay candidates in priority order. CapyToolkit performs the same ICE gathering and connectivity check sequence that a WebRTC application would, so the candidate types and NAT classification you see here match what your application experiences.
A practical example of ICE restart occurs when a laptop user moves from the office Wi-Fi to a cellular hotspot. The initial host candidate bound to the office LAN becomes unreachable; the ICE agent detects the failure through STUN keepalive timeouts, triggers a new gathering cycle, and discovers a new host candidate on the cellular interface. Because the ICE restart reuses the existing signaling connection and media sessions, the user experiences only a brief audio glitch rather than a full call drop. This handoff behavior is a core reason WebRTC is suitable for mobile applications where network changes are frequent.
ICE failures and their causes
ICE fails when no candidate pair passes connectivity checks. Symmetric NAT causes failure by assigning different external ports for the STUN server and peer, making the reflexive candidate unreachable from the peer.4 Firewall rules blocking UDP on non-standard ports prevent STUN requests from reaching the peer. Missing TURN configuration means no relay candidates are generated, leaving no fallback path. Yet even when ICE succeeds, the selected candidate type (revealed by this tool's ICE candidate type display) determines the actual path quality: relay adds a server hop; srflx uses the direct NAT traversal path. CapyToolkit displays the active candidate type for each test, so you can determine whether your connection is routing directly between peers or traversing a relay server, which is the first step toward diagnosing unexpected latency in any WebRTC application.
Trickle ICE and its effect on connection establishment time
Standard ICE waits for all candidates to be gathered before beginning connectivity checks, which can take several seconds when TURN server responses are slow. Trickle ICE (defined in RFC 8838) allows candidates to be sent to the remote peer as they are discovered, so connectivity checks begin immediately when the first candidates arrive. Host and server-reflexive candidates are typically discovered within 100 to 500 ms; TURN relay candidates may take 1 to 2 additional seconds on a distant server. Trickle ICE allows faster candidates to be tested while slower TURN candidates are still being gathered in parallel.5
All major browsers implement trickle ICE by default. The RTCPeerConnection.onicecandidate event fires for each candidate as it is discovered; sending this candidate to the remote peer immediately rather than waiting for gathering to complete implements trickle ICE at the signaling layer. Using trickle ICE reduces perceived connection time by 1 to 3 seconds compared to batched candidate exchange, which is especially noticeable on high-latency signaling paths.
The end-of-gathering signal and why it matters
When gathering is complete, the onicecandidate event fires with a null candidate value. This null event signals that all candidates have been sent and the candidate set is final. Signaling layers that implement trickle ICE must relay this end-of-gathering signal to the remote peer so its ICE agent knows no more candidates will arrive.6 Ignoring the null event in a custom signaling implementation causes the remote agent to wait indefinitely for additional candidates, preventing the connection from completing even when a working candidate pair has already been found.
ICE lite and how media servers simplify the ICE role
ICE lite is a simplified implementation defined in RFC 8445 for endpoints that are always publicly reachable and have no NAT to traverse. A server with a direct public IP does not need to gather server-reflexive or relay candidates; its host candidate is already globally reachable. ICE lite skips full candidate gathering and connectivity check initiation, reducing server CPU overhead significantly compared to a full ICE implementation.
WebRTC media servers including Janus, Jitsi Videobridge, and Cloudflare Calls use ICE lite because they operate on servers with public IPs.7 The connecting browser performs full ICE while the server performs ICE lite: the browser gathers all its candidates and initiates connectivity checks; the server only processes incoming checks and responds to them. Deploying a WebRTC media server on a VPS with a direct public IP makes ICE lite viable, eliminating server-side candidate gathering and pair testing overhead entirely.
When ICE lite is not appropriate
ICE lite must not be used by endpoints behind NAT. A device behind a home router that uses ICE lite would advertise only its LAN IP as a candidate, which is unreachable from the internet, causing all ICE connectivity checks from external peers to fail. ICE lite is appropriate only for infrastructure deployed on servers with direct public IPv4 or IPv6 addresses, where no NAT translation occurs on the path to the internet.
Try in the tool
What to look for
- Typical ICE gathering time 1 to 5 seconds
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
A. Keranen, C. Holmberg, and J. Rosenberg, "Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal," RFC 8445, IETF, July 2018. https://www.rfc-editor.org/rfc/rfc8445.html
- 2.
Mozilla Developer Network, "RTCIceCandidate.type," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate/type
- 3.
Mozilla Developer Network, "RTCPeerConnection.restartIce()," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/restartIce
- 4.
webrtchacks, "Detecting Symmetric NAT," webrtchacks.com, accessed June 2026. https://webrtchacks.com/symmetric-nat/
- 5.
E. Ivov and J. Uberti, "Trickle ICE: Incremental Provisioning of Candidates for the Interactive Connectivity Establishment (ICE) Protocol," RFC 8838, IETF, January 2021. https://www.rfc-editor.org/rfc/rfc8838.html
- 6.
W3C, "WebRTC 1.0: Real-Time Communication Between Browsers," www.w3.org, accessed June 2026. https://www.w3.org/TR/webrtc/
- 7.
Janus Gateway, "ICE Lite mode," github.com, accessed June 2026. https://github.com/meetecho/janus-gateway
ICE is the overall connectivity establishment protocol. STUN (Session Traversal Utilities for NAT) is a helper protocol ICE uses to discover public IP:port pairs. TURN (Traversal Using Relays around NAT) is a relay server ICE uses when direct connectivity fails. CapyToolkit performs the same ICE gathering and connectivity check sequence that a WebRTC application would. ICE orchestrates both STUN and TURN to find the best working connection, so the candidate types and NAT classification you see here match what your application experiences.
ICE finds the highest-priority working path, not necessarily the lowest-latency one. The priority order (host over srflx over relay) maps to the typical latency order but not always. A relay candidate through a nearby TURN server may have lower latency than an srflx candidate routing through a distant ISP peering point, but ICE would still prefer srflx.
ICE gathering and connectivity checks typically complete within 1 to 5 seconds on most networks. Slow STUN server responses or large numbers of candidate pairs can extend this. Trickle ICE, the standard mode in browsers, starts connectivity checks as candidates arrive rather than waiting for full gathering, reducing perceived connection time.
Trickle ICE is an extension to ICE that allows candidates to be sent to the remote peer incrementally as they are gathered, rather than waiting for all candidates to be collected before any exchange begins. This reduces connection establishment time, especially for TURN candidates that require network round-trips to allocate.
Yes, through ICE restart. If the active candidate pair fails (STUN keepalive receives no response), ICE can initiate a new gathering and connectivity check cycle. This enables seamless network handoff, for example when switching from Wi-Fi to a mobile data connection. The application may observe a brief pause during the restart.
What Is a STUN Server?
To establish a WebRTC connection through a NAT router, each peer must know its own public IP address (information the NAT router holds but does not expose to the devices behind it). A STUN server provides this information by acting as a mirror: when a browser sends a STUN binding request, the server reads the source IP and port from the UDP packet (which reflects the NAT router's external address) and sends it back. The browser reads this reflected address and uses it as a server-reflexive ICE candidate for the WebRTC connection.1
What is a STUN server?
RFC 8489) is a lightweight network service that responds to binding requests from clients with the public IP address and port the NAT device assigned to the client's outbound connection. STUN servers do not relay media; they only provide address discovery. A standard STUN interaction involves one UDP exchange: the client sends a binding request; the server responds with the XOR-MAPPED-ADDRESS attribute containing the public IP:port pair.2How STUN discovers public IP and NAT type
When a browser sends a STUN binding request to a server like stun.l.google.com:19302, the packet travels through the home router, which performs NAT and substitutes the router's WAN IP and an assigned external port for the device's LAN IP. The STUN server reads these values from the UDP header and writes them into the binding response. Receiving this response, the browser now knows its public IP:port pair and can include it as a server-reflexive ICE candidate in the SDP. Consequently, the ICE peer at the other end can attempt to reach this public IP:port when executing connectivity checks. CapyToolkit sends binding requests to multiple STUN servers and compares the returned external ports to determine whether your NAT assigns the same port for different destinations (cone NAT) or different ports (symmetric NAT), which is the fundamental distinction that determines whether direct WebRTC connections will succeed.
STUN limitations: what STUN cannot do
STUN only provides address discovery; it cannot relay traffic. When symmetric NAT prevents direct peer-to-peer connectivity, STUN alone cannot help because the NAT assigns different external ports for different destinations. Furthermore, STUN operates over UDP by default (port 3478), which means STUN fails on networks that block all UDP traffic. STUN also cannot work through firewalls that block inbound connections on the discovered port even after the outbound binding request succeeds.
Why every WebRTC deployment needs both STUN and TURN
In all these cases, TURN relay is required. Building on this, every WebRTC deployment that targets general internet users needs both STUN and TURN: STUN for direct connections and TURN as the universal fallback.3 CapyToolkit uses STUN for address discovery only and does not relay any traffic through its own infrastructure, so the public IP you see here is discovered through the same STUN protocol that any WebRTC application would use.
The combination is essential because STUN discovers the address but cannot guarantee connectivity. A cone NAT with STUN-discovered addresses still requires TURN when the peer is also behind a cone NAT with port restrictions, or when a firewall blocks the direct path after discovery. The STUN+TURN pairing ensures that every connection attempt either succeeds directly (using STUN-discovered addresses) or falls back to relay (using TURN). Removing STUN to save TURN resources is counterproductive; direct connections via STUN-discovered addresses are dramatically lower latency and lower server cost than relay, so maximizing direct connections through STUN is the primary cost optimization for any WebRTC deployment.
Public STUN servers and when to use your own
Google operates stun.l.google.com:19302, the most widely used public STUN server.4 Cloudflare and other providers also maintain public STUN endpoints. Public STUN servers have extremely high availability and are suitable for production use for the address-discovery function. Yet public STUN servers do not support TURN relay; they only handle binding requests. For TURN relay, you need a dedicated TURN server with credentials configured in the WebRTC ICE server list. Self-hosting a STUN/TURN server on Coturn provides both discovery and relay in a single server, useful for deployments requiring TURN functionality in a specific geographic region. CapyToolkit uses public STUN servers from Google and Cloudflare to ensure reliable address discovery for the P2P test, which means the public IP you see here matches what any WebRTC application would discover using the same widely trusted public infrastructure.
Running Coturn as a combined STUN and TURN server
Coturn is the most widely deployed open-source STUN and TURN server implementation. Installing it on a Linux VPS provides both address-discovery and relay functionality from a single process. The package is available in default Linux repositories: running apt install coturn on Ubuntu or Debian systems installs the server and its dependencies. After installation, the primary configuration file at /etc/turnserver.conf controls listening ports, credentials, and relay behavior.
The minimum Coturn configuration for production use requires four settings in turnserver.conf: listening-ip set to the server's public IP, fingerprint enabled, lt-cred-mech enabled for long-term credential authentication, and at least one user credential line. The server listens on UDP port 3478 for STUN binding requests and TURN relay requests by default. Adding tls-listening-port=5349 enables TURN over TLS for clients on networks that block non-TLS UDP traffic.
TURN relay ports and firewall requirements for Coturn
Coturn allocates relay ports from a configurable range set by min-port and max-port in turnserver.conf. Each active relay session uses one UDP port from this range on the server. For a Coturn server behind a firewall, the firewall must allow inbound UDP on the listening port (3478), the TLS port (5349), and the full relay port range. A relay range from 49152 to 65535 provides over 16,000 simultaneous relay sessions, which is sufficient for most production WebRTC deployments without additional tuning.5
STUN probe failures: diagnosing UDP blocking and fallback options
A STUN probe that returns no reflexive candidates means either UDP port 3478 is blocked between the client and the STUN server, or the server is unreachable. On corporate and school networks, outbound UDP to non-standard ports is frequently blocked as a default firewall policy. The symptom in this tool is a failed probe with no public IP displayed; the browser sent a binding request that never reached the server or whose response was blocked on the return path.
Diagnosing UDP blocking from the command line uses the stunclient tool from the stuntman package. Running stunclient stun.l.google.com 19302 sends a STUN binding request and prints the result including the public IP, or reports a timeout if UDP is blocked at the network level. Confirming the block points directly to the solution: TURN over TLS on port 443 bypasses most corporate firewalls because outbound port 443 is permitted by almost all network policies.6
TURN on port 443 as the universal firewall fallback
Coturn supports STUN binding requests on the TLS listening port (5349) alongside TURN relay. Configuring your WebRTC application to use a TURN server with transport=tcp and port 443 provides a connection path that succeeds on nearly all corporate and guest Wi-Fi networks where standard UDP is blocked. The tradeoff is slightly higher RTT from TCP acknowledgment overhead compared to UDP's direct datagram delivery, but this tradeoff is preferable to a total connection failure on restricted networks.
Try in the tool
What to look for
- Default STUN port UDP 3478
- TURN over TLS port 5349 (or 443 as a firewall-friendly fallback)
- Public Google STUN server stun.l.google.com:19302
- Typical Coturn relay port range 49152-65535, over 16,000 simultaneous sessions
STUN only discovers addresses; it cannot relay traffic. Every general-purpose WebRTC deployment needs a TURN fallback as well.
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
M. Petit-Huguenin et al., "Session Traversal Utilities for NAT (STUN)," RFC 8489, IETF, February 2020. https://www.rfc-editor.org/rfc/rfc8489.html
- 2.
M. Petit-Huguenin et al., "Session Traversal Utilities for NAT (STUN)," RFC 8489, IETF, February 2020. https://datatracker.ietf.org/doc/rfc8489/
- 3.
webrtchacks, "Detecting Symmetric NAT," webrtchacks.com, accessed June 2026. https://webrtchacks.com/symmetric-nat/
- 4.
IANA, "Service Name and Transport Protocol Port Number Registry," iana.org, accessed June 2026. https://www.iana.org/assignments/service-names-port-numbers
- 5.
Coturn Project, "Coturn: Open Source TURN and STUN Server," github.com, accessed June 2026. https://github.com/coturn/coturn
- 6.
Debian Manpages, "stunclient(1)," manpages.debian.org, accessed June 2026. https://manpages.debian.org/testing/stuntman-client/stunclient.1
No. STUN discovers your public IP address using a single UDP exchange but cannot relay traffic. CapyToolkit uses STUN for address discovery only and does not relay any traffic through its own infrastructure. TURN provides relay services, forwarding encrypted media between two peers when direct connectivity fails. TURN servers implement the STUN protocol as a subset; a TURN server can respond to STUN binding requests, but a STUN-only server cannot provide relay.
For address discovery only, public STUN servers from Google or Cloudflare work well for production use. If your application needs TURN relay, you need a private TURN server since public STUN servers do not handle relay. Coturn is the most widely deployed open-source STUN/TURN server implementation.
Yes. STUN works for both IPv4 and IPv6. On an IPv6 connection, the STUN server returns the device's global IPv6 address, which is typically a host-level public address without NAT. ICE on IPv6 often produces host candidates directly, bypassing the need for STUN in the address discovery step.
Google's stun.l.google.com:19302 and Cloudflare's STUN server have extremely high availability and respond within milliseconds from most global locations. Using two different servers allows the tool to compare external port assignments between requests, which determines whether the NAT type is symmetric or cone.
No. A STUN server only sees the source IP and port of the UDP packets you send to it, which is the same information any internet server sees from any connection. No application data, WebRTC media, or content passes through a STUN server; it only mirrors back the address information already visible in the packet header.
What Is Round-Trip Time (RTT)?
Whenever a packet travels from one endpoint to another and a response returns, the elapsed clock time is the round-trip time. RTT captures the full network path in both directions (outbound latency plus return latency), making it the standard measure for interactive protocols where both parties must send and receive. For voice calls, gaming, and WebRTC, RTT determines how much delay separates an action from its consequence at the other end.1
What is round-trip time?
ping) or application-layer probes such as the UDP probes in this tool.2Components of RTT in a peer-to-peer connection
RTT consists of four delay components added together in both directions. Propagation delay is determined by physical distance; fiber carries light at roughly 200,000 km/s, so 1,000 km of path adds approximately 5 ms in each direction. Transmission delay is negligible for small probe packets on modern gigabit links. Queuing delay varies with router load; an idle router adds under 1 ms while a congested router may add 20 to 50 ms per packet. Processing delay in home routers is typically 0.5 to 2 ms. Consequently, RTT between two home connections on the same city block is typically 10 to 20 ms, mostly queuing and processing overhead rather than propagation.
RTT versus one-way latency
RTT is the sum of outbound and return latency. For symmetric connections with similar infrastructure on both paths, one-way latency is approximately RTT divided by 2. Yet in practice, asymmetric routing is common; the outbound and return paths may traverse different routers, peering points, and ISP links, making the two directions unequal.
How asymmetric routing makes one-way latency differ from half the RTT
Building on this, some WebRTC statistics implementations expose one-way delay separately using RTCP sender reports, which reveals asymmetric paths that RTT averaging hides.3 Most latency-sensitive applications care about the total RTT for interactive communication, since both the action and the response must complete before the user can react. CapyToolkit's RTT measurement includes NAT traversal and any relay overhead because the probes travel over the ICE-selected path, which is the path your application traffic actually follows.
RTT benchmarks for real-time applications
Below 30 ms RTT is excellent for all real-time applications; users perceive no delay in gaming, voice, or video. Between 30 and 100 ms is good and acceptable for all common use cases with minor perceptible delay in fast-paced gaming. Between 100 and 200 ms is acceptable for voice and video but noticeable in competitive gaming. Above 200 ms, voice call timing feels unnatural and turn-based gaming becomes frustrating. Above 300 ms, conversations develop a satellite-call feel where speakers must pause to avoid interrupting. The ITU-T G.114 standard recommends a maximum one-way delay of 150 ms for interactive voice, corresponding to 300 ms RTT.4
Reading RTT from the WebRTC Statistics API
RTCPeerConnection.getStats() exposes round-trip time measurements collected by the browser's ICE agent. The RTCIceCandidatePairStats dictionary for the nominated candidate pair includes a currentRoundTripTime field measured in seconds, representing the most recent ICE STUN keepalive round-trip time. Multiplying by 1000 converts this value to milliseconds, which matches the unit this tool's display uses. The roundTripTimeMeasurements field in the same stats object counts how many RTT samples have been collected; a low count early in the connection is normal as the ICE agent accumulates measurements.
Polling getStats() every 500 ms and logging the currentRoundTripTime values reveals RTT trends over the connection lifetime. The totalRoundTripTime field (the sum of all RTT samples) divided by roundTripTimeMeasurements produces an average that is more stable than any single sample. Chrome's chrome://webrtc-internals page graphs this data live for all active connections, providing the same view without modifying application code.5
Accessing RTT through built-in browser diagnostic tools
Chrome's chrome://webrtc-internals page displays live RTCIceCandidatePairStats for all active connections, including the current RTT and a graphed history over the session. Firefox's about:webrtc provides equivalent data in a similar interface. Opening either page during a call or test session gives you the same RTT data the getStats() API provides, without adding any instrumentation or logging to the calling application itself.
How TURN relay adds RTT overhead and how to minimize it
Relay RTT equals the direct peer-to-peer path RTT plus two additional hops: the round-trip from the first peer to the TURN server, and the round-trip from the TURN server to the second peer. For a TURN server located geographically between the two peers, the relay RTT may be only slightly higher than the direct path. For a TURN server on a different continent from one or both peers, the relay hop adds 100 to 200 ms of purely geographic overhead that the application cannot reduce without moving the relay server.6
Minimizing relay RTT requires deploying TURN servers in the same geographic regions as your users. Cloud providers including AWS, Google Cloud, and Azure offer data center locations that allow placing a Coturn instance within 20 to 30 ms of most regional user populations. Running multiple TURN servers in different regions and directing each peer pair to its nearest server keeps relay overhead under 40 ms for most global user distributions.
Identifying relay overhead by comparing candidate type and RTT
The relay overhead is visible as the RTT difference between sessions where the ICE candidate type is relay versus srflx. Testing the same two-peer connection with iceTransportPolicy: "relay" versus the default policy isolates the relay contribution to RTT. For production WebRTC systems, logging both the candidate type and the RTT for each session gives you the data to track relay overhead across your user base and identify whether additional regional TURN deployments would materially reduce average session RTT.
A practical measurement approach is to run the P2P test twice from the same endpoints: once with the default ICE policy (allowing direct connections) and once with iceTransportPolicy forced to "relay". The difference in reported RTT between the two runs is the pure relay overhead. If the default policy already selected relay (common with symmetric NAT), the difference will be minimal because both tests used the same relay path. If the default selected srflx, the difference reveals the exact cost of the relay hop, which you can compare against the geographic distance to the TURN server to verify the server is optimally placed.
Try in the tool
What to look for
- Light speed in fiber about 200,000 km/s
- Wi-Fi overhead range 1 to 5 ms lightly loaded, 20 to 50 ms congested
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
W3C, "WebRTC 1.0: Real-Time Communication Between Browsers," www.w3.org, accessed June 2026. https://www.w3.org/TR/webrtc/
- 2.
Engineering Toolbox, "Optical Fiber Latency and Propagation Delay," engineeringtoolbox.com, accessed June 2026. https://www.engineeringtoolbox.com/optical-fiber-latency-d_1855.html
- 3.
W3C, "WebRTC Statistics API," www.w3.org, accessed June 2026. https://www.w3.org/TR/webrtc-stats/
- 4.
ITU-T, "One-way transmission time," Recommendation G.114, ITU, May 2003. https://www.itu.int/rec/T-REC-G.114
- 5.
Mozilla Developer Network, "RTCIceCandidatePairStats.currentRoundTripTime," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidatePairStats/currentRoundTripTime
- 6.
Cloudflare, "What is TURN?," developers.cloudflare.com, accessed June 2026. https://developers.cloudflare.com/realtime/turn/what-is-turn/
Yes, conceptually. CapyToolkit's RTT measurement includes NAT traversal and any relay overhead because the probes travel over the ICE-selected path. A ping command sends ICMP echo requests and measures RTT. This tool measures RTT using UDP probe packets over a WebRTC data channel. The mechanism differs but the measurement concept is the same: send a packet, wait for a response, measure elapsed time, which is the path your application traffic actually follows.
WebRTC probe packets travel through the ICE-selected path, which may include NAT traversal overhead, relay routing through a TURN server, or a different network path than ICMP takes. If the ICE candidate type is "relay", the TURN server adds a full relay hop to every packet, significantly increasing RTT compared to direct ICMP.
No. RTT cannot be less than the minimum propagation time for the physical path length. Light travels through fiber at about 200,000 km/s, setting an absolute floor. All real-world RTT includes propagation plus queuing and processing overhead on top of this floor.
Transient queue buildup in a router on the path. When a burst of traffic arrives simultaneously, packets queue up and wait before being forwarded, adding queuing delay. Once the burst clears, queuing delay drops back to near zero. Single spikes indicate transient bursts; sustained elevation indicates persistent congestion.
In most cases, yes. Wired Ethernet eliminates wireless retransmissions and radio contention, which add 1 to 5 ms of variable delay on Wi-Fi. On a lightly loaded 5 GHz network, the difference is small. On a congested 2.4 GHz network, Wi-Fi can add 20 to 50 ms of variable delay compared to wired.
What Is SDP (Session Description Protocol)?
Before audio or data flows between two WebRTC peers, each peer must communicate its capabilities and network addresses to the other. SDP (Session Description Protocol) is the text format that carries this information: a structured list of session parameters including ICE candidates, supported media codecs, DTLS certificate fingerprints, and transport attributes.1 The offer/answer exchange of SDP blobs is the signaling step that precedes every WebRTC connection, and the manual copy-paste of SDP in this tool is exactly what production WebRTC systems automate through signaling servers.
What is SDP?
RFC 4566) is a text-based format for describing multimedia session parameters. In WebRTC, SDP encodes the local peer's ICE candidates, DTLS fingerprint, SRTP key material, supported audio and video codecs, RTP payload type mappings, and media direction (sendrecv, recvonly, sendonly). An SDP offer describes what the initiating peer supports; the answering peer responds with an SDP answer that selects from the offered capabilities. The intersection of offer and answer parameters determines the actual connection configuration.2SDP offer/answer and WebRTC signaling
WebRTC defines an offer/answer model for SDP exchange. The initiating peer calls createOffer() to generate an SDP blob describing its capabilities, then sets it as the local description using setLocalDescription(). This SDP must be sent to the remote peer through a signaling channel (a WebSocket, HTTP POST, or manual copy-paste as in this tool). The remote peer calls setRemoteDescription() with the received SDP, then calls createAnswer() to generate an SDP answer selecting compatible parameters. Consequently, after both peers have set their local and remote descriptions, the ICE agent begins gathering and exchanging candidates for connectivity checking.3 CapyToolkit performs this exact offer/answer exchange using manual copy-paste as the signaling mechanism, which makes the entire process visible and debuggable without needing to set up a WebSocket server or third-party signaling service for testing purposes.
What an SDP blob contains
An SDP blob is a multi-line text string beginning with the version line "v=0". It contains session-level attributes (origin, session name, timing) followed by media descriptions for each stream. Each media description specifies the transport port, protocol (UDP/TLS/RTP/SAVPF), and payload types. Extensions encoded in "a=" attribute lines include ICE credentials (ufrag and password), ICE candidates as "a=candidate:" lines, DTLS fingerprint as "a=fingerprint:", media direction, and RTP extension mappings.4 Building on this structure, SDP in this tool contains only a data channel description (no audio or video), since the tool measures network metrics rather than media quality.
How to read SDP for debugging connection failures
Understanding the SDP structure helps you debug connection failures because many common errors (codec mismatches, missing fingerprints, or payload type conflicts) are visible in the raw SDP text before the ICE negotiation even begins. CapyToolkit displays the raw SDP so you can copy it between browser windows for manual signaling, which helps you understand exactly what parameters your negotiation produced.
SDP and security in WebRTC
The DTLS fingerprint in SDP is the security anchor for a WebRTC connection. When the DTLS handshake completes, each peer verifies that the certificate presented by the remote peer matches the fingerprint included in the SDP. If an attacker intercepts and modifies the SDP to replace the fingerprint, the DTLS handshake fails because the certificate does not match. This makes SDP integrity critical; a signaling channel that can be tampered with compromises the connection security.5 Yet for this tool's diagnostic purpose, the connection is between the same user's two browser windows, making signaling integrity a practical non-concern. CapyToolkit does not transmit your SDP to any server; the exchange happens entirely in your browser when you copy and paste the text between tabs, which means there is no server-side attack surface to worry about during testing.
SDP in the Unified Plan format for multi-track sessions
Chrome migrated from Plan B to Unified Plan SDP in Chrome 72 (2019) and completed the transition in Chrome 93 (2021), removing Plan B support entirely. Unified Plan represents each audio and video track as a separate m-section (media description block) in the SDP. Plan B represented multiple tracks of the same type as separate a=ssrc lines within a single m-section. The distinction matters when debugging SDP from older deployments or when reading SDP generated by mixed-version peers where Plan B formatting may still appear.6
In Unified Plan SDP, each track has its own m-section with its own ICE credentials, DTLS fingerprint, and codec list. A video call with one audio track and one video track produces an SDP with two m-sections: one m=audio and one m=video. Simulcast layers (multiple resolution variants of the same track) are encoded as RID attributes within a single m-section rather than as separate m-sections. Unified Plan SDP is longer than Plan B SDP for multi-track sessions, but its structure maps more directly to individual tracks, which simplifies programmatic inspection and debugging.
Parsing SDP programmatically for debugging
The sdp-transform npm package parses a raw SDP string into a JavaScript object for programmatic inspection. Installing it and calling sdpTransform.parse(sdpString) returns a structured representation of all session and media attributes. Extracting specific fields such as ICE credentials, codec payload types, or fingerprint values becomes straightforward compared to manually parsing the raw multi-line text format. For debugging unexpected connection failures, inspecting the parsed SDP for codec mismatches or missing fingerprints is faster than reading the raw SDP output line by line.
Common SDP errors and how to diagnose them in production
The most common SDP error in WebRTC applications is an InvalidAccessError thrown by setRemoteDescription() when the answer SDP contains a codec or payload type not present in the offer. A typical cause is modifying the SDP offer to remove a codec before sending it to the remote peer, then receiving an answer that references that codec by payload type number. The browser rejects the answer because the payload type has no matching entry in the negotiated offer, causing the connection to fail at the description-setting stage.
A second common error is an OperationError thrown by setLocalDescription() when called before the previous offer/answer cycle resolves. This occurs when setLocalDescription() is called concurrently on the same connection, producing a state conflict in the ICE agent. The fix is waiting for the promise returned by each setLocalDescription() or setRemoteDescription() call to resolve before calling the next one, ensuring sequential state transitions throughout the signaling exchange.
Using chrome://webrtc-internals for live SDP inspection
Chrome's chrome://webrtc-internals page logs every SDP offer, answer, and ICE candidate exchanged during active RTCPeerConnection sessions. Opening this page in a separate tab before starting a WebRTC session captures the full SDP exchange for inspection. The event log shows the exact SDP string passed to each setLocalDescription() and setRemoteDescription() call, along with timestamps and any errors thrown. This is the fastest available method to diagnose SDP negotiation failures without adding debug logging to the application code itself.
For production debugging, you can correlate the SDP logs from chrome://webrtc-internals with your application's internal logs to pinpoint exactly which offer/answer exchange failed and why. The internals page also shows the ICE candidate gathering state and connectivity check results alongside the SDP, giving you the complete picture of both the signaling and connectivity layers in one view. Since the page requires no application changes, it works on any deployed WebRTC application, making it invaluable for debugging production issues that only manifest under specific network conditions.
Try in the tool
What this page covers
- Offer/answer sequence createOffer() > setLocalDescription() > (signaling) > setRemoteDescription() > createAnswer()
- "v=0" version line every SDP blob's first line, followed by session-level and per-media descriptions
- a=candidate: lines carry each peer's ICE candidates within the SDP text
- a=fingerprint: the DTLS certificate fingerprint that the handshake verifies against the remote peer's certificate
Open the P2P Network Tester tool to try this yourself.
Open the tool →- 1.
M. Handley, V. Jacobson, and C. Perkins, "SDP: Session Description Protocol," RFC 4566, IETF, July 2006. https://www.rfc-editor.org/rfc/rfc4566.html
- 2.
J. Uberti and C. Jennings, "JavaScript Session Establishment Protocol (JSEP)," RFC 8829, IETF, July 2024. https://datatracker.ietf.org/doc/html/rfc8829
- 3.
Mozilla Developer Network, "RTCPeerConnection.createOffer()," developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer
- 4.
webrtchacks, "Anatomy of a WebRTC SDP," webrtchacks.com, accessed June 2026. https://webrtchacks.github.io/sdp-anatomy/
- 5.
J. Okholm and C. Perkins, "Connection-Oriented Media Transport over TLS in SDP," RFC 8122, IETF, June 2017. https://www.rfc-editor.org/rfc/rfc8122.html
- 6.
webrtchacks, "The Minimum Viable SDP," webrtchacks.com, accessed June 2026. https://webrtchacks.com/the-minimum-viable-sdp/
Yes, SDP is plain text. CapyToolkit displays the raw SDP so you can copy it between browser windows for manual signaling. Each line is an attribute type followed by an equals sign and a value. The format is terse but readable once you know the attribute names. Tools like the Muaz Khan SDP editor and Philipp Hancke's webrtc-externals extension can parse and visualize SDP blobs clearly, which helps you understand exactly what parameters your negotiation produced.
Modern SDP includes extensive ICE candidate lists, codec capability declarations, RTP extension mappings, and security parameters. Each ICE candidate is a separate "a=candidate:" line. A typical WebRTC SDP from a browser includes 20 to 50 lines for a simple data channel session.
Technically yes, but modifying SDP is fragile and browsers may reject modified descriptions. Removing or replacing ICE candidates or DTLS fingerprints will cause the connection to fail. The most common legitimate SDP modification is adjusting codec preferences or bandwidth limits in specialized implementations.
If the answer selects a codec or transport not offered in the offer, setRemoteDescription() throws an error. Both peers must support at least one common codec and the same security parameters. If no compatible intersection exists, the connection cannot be established.
No. SDP is defined in RFC 4566 and predates WebRTC. It originated as part of the SIP (Session Initiation Protocol) ecosystem for VoIP and is used by VoIP phones, SIP trunks, and video conferencing systems as well as WebRTC. WebRTC extends the base SDP format with additional attributes for ICE, DTLS, and SCTP data channels.