When a video call turns choppy, freezes, or simply refuses to connect, guessing rarely gets you to a fix. Chrome ships with a diagnostic page built for exactly this moment: chrome://webrtc-internals. It's the live, in-browser view of the statistics that WebRTC's getStats() API produces for every active call, so there's no extension to install, no code to add, nothing to configure. Open the tab, and the numbers are already there.
This guide walks through what chrome://webrtc-internals actually is, how to open it and capture a session properly, what each section of the page means, and, most usefully, how to map real symptoms (choppy audio, frozen video, calls that won't connect) to the exact fields that explain them, and what to do about it.
Table of contents
chrome://webrtc-internals is a built-in page in Chrome, and the same tool works directly at that address in other Chromium-based browsers such as Brave and Opera. Edge has the identical tool, but at its own address: edge://webrtc-internals. None of these versions generate their own data; each one mirrors what RTCPeerConnection.getStats() is already reporting for every connection, and renders it as live graphs and tables instead of the raw JSON you'd otherwise have to request from the browser yourself.
Under the bonnet, it tracks the lifecycle of every RTCPeerConnection on the page: the SDP offers and answers exchanged during signalling, the ICE candidates gathered, and the connection state as it moves from new to connected (or to failed). None of this requires any instrumentation in your application code, which is why it's usually the first stop when a call misbehaves.
Firefox has its own equivalent, reachable at about:webrtc, exposing broadly similar information: peer connection state, ICE candidate pairs, and stats graphs. The layout and terminology differ enough that a screenshot from one won't map cleanly onto the other, but the underlying concept is the same. Keep in mind that all of this applies to browser clients only. Native mobile apps built directly on libwebrtc, rather than a mobile browser, have no equivalent page at all, so if one participant in a call is on a native app rather than a browser tab, you won't be able to pull their stats this way.
Using chrome://webrtc-internals well comes down to one habit: open it before the call starts, not after something has already gone wrong.
To use it:
chrome://webrtc-internals.PeerConnection entry, graphs, and an event log.If your application opens more than one RTCPeerConnection, which is common with SFU (selective forwarding unit) architectures where each remote participant gets its own connection, you'll see one entry per connection, each identified by its own ID. Check which one corresponds to which participant before you start digging into stats, or you'll end up reading the wrong graph.
The page only records data for the time it's open. This is the single most common mistake developers make with it: if the call already froze five minutes ago and you're only opening the tab now, you've missed the moment the problem occurred. There is no history to scroll back through.
This is exactly the situation you'll run into most often in practice: a user reports that their call broke, but by the time you hear about it, both the call and the tab are long gone. When that happens, chrome://webrtc-internals can't help you retroactively, because there's nothing left to recover. Your best options are to ask the person to reproduce the problem while the tab is open (talk them through opening chrome://webrtc-internals before they rejoin the call), or to fall back on whatever server-side or platform-level monitoring was already running when the problem occurred.
For anything you want to examine later, or hand to a colleague or to support, click 'Create Dump' near the top of the page, then click 'Download' to save the file. This exports everything the page has collected: the peer connection configuration, the full stats history, and the event trace. It's dense. A single session can run to thousands of lines of structured data, so treat the dump as ground truth to search through rather than something to read start to finish. If you're doing this often enough that manual reading becomes a bottleneck, community tools exist that can parse and visualise these dumps for you.
Once a session is running, the page organises information into a handful of areas worth knowing in advance.
At the top of each entry you'll find the configuration passed to the connection, including the list of ICE servers (STUN and TURN) it was given, alongside the current iceConnectionState and connectionState. iceConnectionState moves through new, checking, connected, completed, disconnected, failed, and closed over the life of a connection. Watching it progress from checking to connected tells you whether negotiation is proceeding normally, and a state that lingers on checking for more than a few seconds is usually your first sign of a network path problem.
This table lists every candidate pair Chrome tried and marks which one was ultimately nominated for the connection. Each candidate has a type: host (your own address), srflx (server reflexive, discovered via STUN), prflx (peer reflexive, discovered during connectivity checks), or relay (routed through a TURN server). If the nominated pair is a relay candidate, the call is being routed through a TURN server rather than connecting directly, which adds latency and infrastructure cost but is often what keeps a call alive behind restrictive NATs or firewalls. Seeing relay here isn't a fault in itself, but it's a useful signal when you're also chasing a latency complaint.
WebRTC keeps separate stats for what you send and what you receive. Inbound-rtp stats describe media coming in from the other participant (what you're seeing and hearing from them); outbound-rtp stats describe media you're sending out to them. That distinction matters. If the other person says your video looks frozen, the stats you need are on your outbound side, not your inbound one: inbound describes what's arriving at your end, not what's leaving it.
For each track, the page charts bitrate, frame rate, and resolution over time, alongside counters like framesDecoded (inbound, how many frames you've decoded from what you received) and framesSent (outbound, how many frames you've encoded and sent). A healthy video track holds a stable bitrate and frame rate appropriate to its resolution, and its qualityLimitationReason field on the outbound side simply shows none. A degraded track shows bitrate and frame rate stepping down together, and qualityLimitationReason will tell you whether the constraint is CPU, bandwidth, or something else entirely.
These three fields explain most call-quality complaints, and they're worth understanding properly:
packetsLost is a running count of packets that never arrived. What matters is the rate of change rather than the absolute number. A small, non-increasing count from early in the call isn't cause for concern, whereas a count climbing steadily is.With those fields in mind, most reported symptoms map onto a fairly short checklist. As you work through it, keep two things in mind: which side of the call, inbound or outbound, actually explains the symptom, and whether the cause is even visible from the tab you have open. qualityLimitationReason, for instance, only exists on the sending participant's own outbound-rtp stats. If you're the one experiencing choppy video, that field won't appear in your own tab at all; you'd need a dump from whoever is sending the video to see it. Diagnosing a one-way problem properly often means collecting stats from both ends of the call, not just the end where the symptom showed up.
Choppy or robotic-sounding audio. Check packetsLost and jitter on the audio inbound-rtp stats first (this is what you received, so it's the right place to look if what you're hearing sounds broken). A rising loss count or jitter consistently above roughly 30ms is the usual culprit, and both point towards network instability on one side of the call. If the numbers look fine on your inbound side, ask the other participant to check their outbound stats: the problem may sit on their network, not yours.
Frozen or low-resolution video. Look at the relevant RTP stats: outbound if you're checking why your own video looks bad to others, inbound if you're checking why someone else's video looks bad to you. If bitrate and frame rate are stepping down together, check qualityLimitationReason on the sender's outbound stats. A value of cpu means the sender's machine can't encode fast enough at the current resolution: closing other demanding applications, lowering the capture resolution, or checking that hardware encoding is actually being used are the usual fixes. A value of bandwidth means the network can't sustain the current bitrate: that points towards a weaker connection, a TURN relay adding overhead, or simply asking the app to request a lower resolution from that sender.
Calls that won't connect at all. This is an ICE problem before it's anything else. Check whether iceConnectionState reaches connected, gets stuck on checking, moves to failed, or drops to disconnected. The last two matter differently: disconnected is often transient, a brief network blip that can recover on its own, while failed means ICE has given up and won't recover without a retry. If the state is failed, look at the candidate pairs table alongside the ICE server list from the configuration section. If no relay candidate appears at all, check that a TURN server was actually configured: a restrictive NAT or firewall on one side may have blocked every direct path, and a missing or misconfigured TURN server leaves nothing to fall back on.
On a group call, all of this assumes you're reading the right PeerConnection entry to begin with. Stats from someone else's connection won't tell you anything about the one that's misbehaving.
chrome://webrtc-internals has clear limits, and it helps to know where they are. It's per-browser and per-session: it only shows what one user's Chrome tab saw, for as long as that tab stayed open. It has no concept of other participants, other browsers, or what happened five minutes before you opened it. For a single support ticket, that's often exactly enough. For understanding whether call quality across your whole user base is trending in the wrong direction, it isn't.
That's the gap that production monitoring platforms, including Digital Samba's, are built to close: aggregating quality signals like MOS scores and network performance metrics across every session, rather than asking someone to open a diagnostics tab and read graphs by hand each time. If you want to build that fuller picture yourself, Digital Samba's guide to network performance metrics and guide to SDK video call quality metrics are good starting points. Our guide to testing WebRTC applications covers the same ground from a testing angle.
chrome://webrtc-internals remains the fastest, no-setup way to see what a WebRTC call is actually doing under the surface. Learn to read the packetsLost, jitter, and RTT trio, keep an eye on the ICE candidate pairs table, and you'll be able to diagnose most real-world call problems without reaching for anything else. Beyond a single session on a single browser, pair this habit with proper call quality monitoring so problems show up as trends before they turn into a flood of support tickets. Get in touch at digitalsamba.com if you'd like a hand setting that up.
It's the browser's built-in view of the same statistics WebRTC's getStats() API already collects for each RTCPeerConnection: bitrate, packet loss, jitter, and connection state, displayed as live graphs and tables instead of raw data you'd otherwise have to request yourself.
Open chrome://webrtc-internals in a separate tab before the call starts, let it run for the duration of the call, then click 'Create Dump' followed by 'Download' to save the full stats history and event trace as a file.
Watch the trend, not the raw number. A packetsLost count that keeps climbing signals real loss, while a small, static count early in a call usually doesn't. Jitter above roughly 30ms tends to strain the receiver's buffer enough to affect quality, and round-trip times beyond around 200 to 300ms are where conversation starts to feel disjointed.
Open the ICE candidate pairs table and check which candidate was nominated. If its type is relay, traffic is passing through a TURN server rather than connecting directly, which typically adds some latency to the call.
Firefox exposes similar information at about:webrtc, covering peer connection state, ICE candidates, and stats graphs, though the page layout and terminology don't match Chrome's directly.
Because it only records for as long as the tab stays open. If you open it after the call has already started, or after the problem has already happened, there's no earlier history to look back at. That's why opening it before you join the call matters.