livqenoDocs

RTCDiagnostics

Diagnostics

Real call-quality stats — RTT, jitter, packet loss, bitrate, and codec.

When a user says "the call was bad", you need numbers to find out why: was it their network, their device, or something else? This page shows how to check a call's health and quality. Use it to:

  • show a quality badge in your call screen,
  • attach details to a bug report or support ticket,
  • spot users who keep having bad calls.

All code runs in your app. You'll see some network words; here's what they mean:

WordMeaningWhen it's bad
RTT (round-trip time)How long a packet takes to reach the server and come back.High RTT feels like lag: people talk over each other.
JitterHow uneven packet arrival is.High jitter sounds choppy or robotic.
Packet lossShare of packets that never arrived.Above a few percent, video freezes and audio breaks up.
BitrateHow much data per second a track uses.Low bitrate on video means blurry video.
CodecThe format video is compressed in (e.g. VP8, H.264).Useful when only some devices have problems.
ICEHow the device finds a network path to the media server.failed means no path was found, often a firewall.

There are two methods:

MethodCostUse it for
getDiagnostics()Cheap, instantConnection state, for bug reports
getConnectionStats()Does real work, asyncMedia quality numbers (loss, jitter, bitrate)

Both work the same on Web and React Native (it's the same Room class).

getDiagnostics() — quick connection info

const info = room.getDiagnostics();
// {
//   connectionState, reconnectCount, sdkVersion, platform, browser,
//   iceConnectionState, signalingState,
//   remoteIceConnectionState, remotePeerConnectionState,
// }

You can call it any time. It never contains a token or a secret, so you can attach it to a bug report as it is.

FieldWhat it tells you
connectionStateLivqeno's connection state. Use this one for your UI.
reconnectCountHow many times the room reconnected on its own.
iceConnectionStateThe network (ICE) state, as your device sees it.
signalingStateThe browser's signaling state.
remoteIceConnectionStateThe network (ICE) state, as the media server sees it.
remotePeerConnectionStateThe connection state, as the media server sees it.
sdkVersion, platform, browserYour setup, for a bug report.

The local and remote values can disagree. That's useful: "server says failed, browser says connected" tells you where the problem is.

getConnectionStats() — call quality numbers

const stats = await room.getConnectionStats();
// {
//   connectionState,
//   connectionQuality,      // 'excellent' | 'good' | 'poor' | 'lost' | 'unknown' — the SFU's own read
//   local: TrackStats[],    // one entry per track you've published
//   remote: TrackStats[],   // one entry per track you've subscribed to
// }

Each TrackStats entry looks like this:

{
  kind, direction,          // 'send' | 'receive'
  bitrateBps,                // undefined on a track's very first sample — there's nothing yet to diff against
  packetsLost, packetLossPercent,
  jitterMs,
  roundTripTimeMs,           // only ever present on a send-direction track — WebRTC never reports a receiver's own RTT
  codec,                     // only ever present on a receive-direction video track
  frameWidth, frameHeight, framesPerSecond,
}

This call does real work for every track. Call it every few seconds, not in a tight loop:

setInterval(async () => {
  const stats = await room.getConnectionStats();
  console.log('quality:', stats.connectionQuality);
  for (const track of stats.remote) {
    if (track.packetLossPercent && track.packetLossPercent > 5) {
      console.warn(`${track.kind} losing packets: ${track.packetLossPercent.toFixed(1)}%`);
    }
  }
}, 5000);

On React Native, it's the same call. room is what livqeno.join() returned:

const stats = await room.getConnectionStats();

See stats on the server

You won't always have the user's device in front of you. That's why the same numbers are also sent to Livqeno, where your team can look them up later from a support ticket.

If your SDK version sends stats as telemetry, the numbers show up in Livqeno's Connection records automatically. No extra code needed. View them in the dashboard, or with livqeno connections inspect <id>.

When there are several tracks, they're combined into one number per field:

FieldHow it's combined
RTTFrom a track you send
Jitter, packet lossThe worst value across all tracks
BitrateAdded up across all tracks

This works with every client SDK, including Flutter.

Common errors

ErrorCauseFix
getConnectionStats is not a function (Flutter)Flutter doesn't have it yet.Use room.connectionStateChanges for state, and server-side stats (above) for quality.
Every TrackStats.bitrateBps is undefinedIt's the first sample after a track started.Wait for the second sample.

Tips for production

  • Check stats on a timer (every 5 seconds is a good default). Never in a render loop.
  • Use connectionQuality as the main answer. It's pushed to you: listen for connectionQualityChanged (or read participant.connectionQuality) rather than polling for it. Only look at the raw TrackStats fields when you need to explain why quality is poor.
  • To check a device and network before a call, run the pre-call test.
  • Diagnostics never include a token, a secret, or personal data. They're safe to log or send to support.

Next steps