Skip to main content
Version: 0.x.x

Monitoring Transport Stats - JavaScript

The getTransportStats() method lets you read a participant's transport-level stats — how much media data is flowing in and out over their transport. It returns the outgoing (uplink) and incoming (downlink) bitrate in kilobits per second (kbps), along with the total bytes sent and received over the transport.

Unlike per-track stats, which describe individual audio or video quality, transport stats describe the pipe itself — the aggregate throughput of the connection. This makes it a lightweight signal for showing connection indicators and detecting network degradation. It can be called for both the local participant and any remote participant.

Why It Matters

A participant's call experience depends heavily on how much data their network can move. With getTransportStats() you can:

  • Show a connection indicator (good / fair / poor) next to each participant.
  • Catch problems early — when a participant's bitrate drops sharply, it often signals trouble before their video or audio actually breaks up.
  • React automatically — for example, suggest switching to audio-only when a participant's connection weakens.
  • Track data usage with the running totals of bytes sent and received.

Return Value

getTransportStats() returns a Promise that resolves to an object with two groups — send (the data the participant is uploading) and receive (the data the participant is downloading).

{
send: {
outgoingBitrate: number | null, // current upload rate, in kbps
totalSentBytes: number | null, // total data sent so far, in bytes
},
receive: {
incomingBitrate: number | null, // current download rate, in kbps
totalReceivedBytes: number | null, // total data received so far, in bytes
},
}
FieldUnitDescription
send.outgoingBitratekbpsAggregate send bitrate across all outbound media streams.
send.totalSentBytesbytesCumulative bytes sent by the participant.
receive.incomingBitratekbpsAggregate receive bitrate across all inbound media streams.
receive.totalReceivedBytesbytesCumulative bytes received by the participant.
note

This method returns a snapshot taken at the moment you call it — it is not an event you subscribe to. To keep your UI up to date, call it on a short interval.

Example Usage

getTransportStats() is available on both the local participant and any remote participant.

let meeting;

// Initialize Meeting
meeting = VideoSDK.initMeeting({
// Configuration options
});

// Read the local participant's transport stats
const stats = await meeting.localParticipant.getTransportStats();
// {
// send: { outgoingBitrate: 850, totalSentBytes: 10485760 },
// receive: { incomingBitrate: 1200, totalReceivedBytes: 20971520 },
// }

Polling for live updates

Because each call returns a one-time snapshot, you poll the method to keep your UI current. Instead of a fixed setInterval, fire the next request only after the previous one resolves — this avoids overlapping calls when the network is slow.

// Track which participants currently have an active stats loop
const activeStatsLoops = new Set();

function startTransportStatsLoop(participant) {
if (activeStatsLoops.has(participant.id)) return;
activeStatsLoops.add(participant.id);

const pollTransportStats = async () => {
while (activeStatsLoops.has(participant.id)) {
try {
const stats = await participant.getTransportStats();
if (stats) {
updateConnectionUI(participant, {
up: stats.send.outgoingBitrate ?? 0,
down: stats.receive.incomingBitrate ?? 0,
});
}
} catch (err) {
console.error("getTransportStats error", participant.id, err);
}

// Wait 1s after each result before firing the next request
await new Promise((resolve) => setTimeout(resolve, 1000));
}
};

pollTransportStats();
}

function stopTransportStatsLoop(participantId) {
activeStatsLoops.delete(participantId);
}

Start a loop for the local participant once the meeting is joined, and for each remote participant as they join. Stop the loop when a participant leaves.

meeting.on("meeting-joined", () => {
startTransportStatsLoop(meeting.localParticipant);
});

meeting.on("participant-joined", (participant) => {
startTransportStatsLoop(participant);
});

meeting.on("participant-left", (participant) => {
stopTransportStatsLoop(participant.id);
});
caution

Right after a participant joins — before they start sending or receiving any media — the bitrate and byte values may come back as 0 or null. Treat these as "no data yet" rather than a real measurement, and default them to 0 in your UI as shown above.

API Reference

The API references for all the methods utilized in this guide are provided below.

Got a Question? Ask us on discord