demo · v141

Zero-Byte Row

Because Chrome 141 creates the stats object right after SDP, polling code that divides by bytesSent to compute bitrate will see zeroes for the first second or two. Filter on packetsSent > 0 or check r.timestamp deltas; otherwise your bitrate UI flashes "0 kbps" before settling.

Heads up Requires Chrome 141+. The bug isn't in the spec change — it's in apps' assumption that the existence of an outbound-rtp row meant data was already flowing.
checking support…

Simulated frame-by-frame polling of an outbound-rtp row, showing the new "exists but empty" rows you have to handle:

poll #timestamppacketsSentbytesSentbitrate (kbps)note

defensive polling

let prev = null;
async function poll() {
  const stats = await pc.getStats();
  for (const r of stats.values()) {
    if (r.type !== "outbound-rtp") continue;
    if (r.packetsSent === 0) {
      // 141+: row exists, no data yet. Don't divide by zero, don't render 0kbps
      continue;
    }
    if (prev && prev.ssrc === r.ssrc) {
      const dt = (r.timestamp - prev.timestamp) / 1000;
      const dBytes = r.bytesSent - prev.bytesSent;
      const kbps = (dBytes * 8 / 1000) / dt;
      renderBitrate(kbps);
    }
    prev = r;
  }
}

why this angle

This is the operational follow-on to the spec-alignment change. The "zero-byte rows" exist in Safari already; Chrome 141 starts emitting them too. Sites that have only ever tested on Chrome will hit this for the first time. The fix is one line — skip rows where packetsSent === 0 — but the failure mode (UI flashing "0kbps") is noisy enough to warrant the explicit walk-through.

see also

scenario focus

Select a scenario to focus its rendered example and summary.