TURN and STUN Statistics
Updated
The Statistics API returns usage rollups for the entire account or for a specific channel. Reporting data is rolled up hourly, so very recent traffic may not appear immediately.
Use GET /_stats for account-wide usage. Add a channel name, as in GET /_stats/{channel}, to limit the results to that channel. Authenticate both forms with HTTP Basic authentication from a trusted backend.
Request Parameters
/_stats/_stats/{channel}| Parameter | Description |
|---|---|
l |
Measurement to return. Use one of the supported names below. |
gs |
Inclusive UTC start date of the requested period as YYYY:MM:DD. |
ge |
Inclusive UTC end date of the requested period as YYYY:MM:DD. |
break=1 |
Return the period as grouped intervals instead of only an aggregate. |
Supported measurement names:
turn:session: TURN session duration in secondsturn:recv: bytes received by TURNturn:sent: bytes sent by TURNstun:session: STUN session duration in seconds
Use the singular names exactly as shown. A query URL has one ?; join additional parameters with &.
Example
Omit the channel name to return an aggregate for the entire account:
curl --user "$XIRSYS_IDENT:$XIRSYS_SECRET" \
"https://global.xirsys.net/_stats?l=turn:sent&gs=2026:05:01&ge=2026:05:24"Include the complete channel name to limit the results to one channel. This example also requests grouped intervals:
curl --user "$XIRSYS_IDENT:$XIRSYS_SECRET" \
"https://global.xirsys.net/_stats/myChannel?l=turn:sent&gs=2026:05:01&ge=2026:05:24&break=1"The channel-specific request from Node.js 18 or later:
const channel = process.env.XIRSYS_CHANNEL;
const encodedChannel = encodeURIComponent(channel);
const auth = Buffer.from(
`${process.env.XIRSYS_IDENT}:${process.env.XIRSYS_SECRET}`
).toString('base64');
const params = new URLSearchParams({
l: 'turn:sent',
gs: '2026:05:01',
ge: '2026:05:24',
break: '1'
});
const response = await fetch(
`https://global.xirsys.net/_stats/${encodedChannel}?${params}`,
{ headers: { Authorization: `Basic ${auth}` } }
);
const data = await response.json();
if (!response.ok || data.s !== 'ok') {
throw new Error(`Statistics request failed (${response.status})`);
}
console.log(data.v);URL-encode the complete channel name. Choose a reporting range that includes completed hourly rollups.
Understand Aggregate Fields
An aggregate result includes count, sum, max, and min. For example:
{
"count": 100,
"max": 2000000,
"min": 1000,
"sum": 100000000
}| Field | Meaning |
|---|---|
count |
The number of stat records included in the result: 100 in this example. |
sum |
The total of the v values from those records: 100,000,000. |
max |
The largest single v value: 2,000,000. |
min |
The smallest single v value: 1,000. |
For turn:recv and turn:sent, each v value is bytes. The example therefore represents 100 samples totaling 100,000,000 bytes (about 95.37 MiB), with a largest sample of 2,000,000 bytes, a smallest sample of 1,000 bytes, and a calculated average of 1,000,000 bytes per sample.
For turn:session and stun:session, each v value is a duration in seconds. sum is the total session duration in seconds, while count is the number of session records included.
Interpreting count: it is the number of stat records reduced, not always a user-visible connection count. The dashboard uses count for the STUN and TURN connections chart, but uses sum for bandwidth and session-duration reporting.