The Traffic & Bandwidth screen answers one question: for this org, how many bytes moved, in which direction, over which transport, in the last N minutes. It is backed by a single procedure, traffic.overview, which reads two pre-aggregated ClickHouse rollups, unions them, and folds the result into a per-minute series plus per-modality totals.
The console exposes five window presets — 15 min, 30 min, 1 hour, 6 hours, 24 hours — and mirrors the selection into the w query parameter so a window is shareable by URL. The query refetches every 30 seconds, and the refresh button forces a refetch.

Where the numbers come from

Two independent collectors feed this screen. They are unioned, not merged: a row from either side becomes a (modality, bucket) row in the result. The engine meter is the instrumentation that TeleQuick modules call when they move bytes. It already knows the modality, direction, and packet counts, so its rows pass through nearly untouched. The QUIC sampler is different in kind. It walks live QUIC connections and samples transport counters per (subject_kind, subject_id). Before it lands in this view it is grouped down to subject_kind per bucket, with subject_id collapsed into a distinct-connection count. That grouping is where packet counts are lost and where “sessions” gets its meaning. After the union, rows are re-aggregated per (modality, bucket): bytes_in, bytes_out, packets_in, and packets_out are summed; sessions takes the maximum, not the sum. A row whose modality is empty is bucketed under unknown.

Modality keys

The modality key is the raw string from the collector. The console maps known keys to a display label and a stable colour; an unrecognised key still renders, labelled with the raw key and coloured from a fallback palette. A newly wired transport therefore appears on the chart before anyone teaches the UI about it. Keys sourced from the engine traffic meter: Keys sourced from the QUIC sampler’s subject_kind: voice and voice_rtp are distinct keys from distinct collectors and are not deduplicated. A call whose media rides QUIC to the relay and RTP to a carrier contributes to both rows. Read the breakdown table as “bytes per transport”, not “bytes per call”. Two historical gaps are worth knowing when you look at older windows. The QUIC sampler rows were dark until 2026-09-10, because the sampler only walked the native quiche listener while production served MoQT over lsquic — none of the subject_kind modalities appeared before that date. The inference, turn, mqtt, wt_media, whatsapp, and compute keys were wired on the same date; those modules moved bytes before then and reported none.

Why some modalities report no packets

The union writes literal zeros for packets_in and packets_out on every QUIC-sampler row. The sampler’s grouping step discards per-subject packet counters, so there is nothing to carry forward. Byte counts on those rows are real; packet counts are simply unknown and are represented as zero rather than as null. Consequently packetsIn / packetsOut in the byModality payload are only meaningful for engine-meter modalities. The console’s breakdown table does not render them at all, which avoids showing a QUIC modality that moved gigabytes next to a packet count of 0. If you consume the procedure directly, apply the same caution: do not derive average packet size or loss ratios for a QUIC-sampled modality.

Bucketing, lag, and the query window

Both rollups are pre-bucketed to one minute. The procedure selects rows where bucket > now() - INTERVAL <windowMinutes> MINUTE, so the window is a rolling wallclock range, and the resolution of the series is always one minute regardless of which preset you pick — a 24-hour window returns 1-minute buckets, not coarser ones. Because bucketing is on wallclock minute boundaries, a session that spans a boundary is split across buckets. There is no attribution of a whole session to its start minute. New traffic appears once the minute bucket it belongs to has been rolled up and becomes visible to the query. The console’s empty state describes this as usually within about a minute; the screen’s own 30-second refetch means you may need one or two polls after a session starts before its first bucket is on the chart. The procedure’s input schema caps windowMinutes at 1440. For anything longer-range than that, use the per-call records described in Telemetry rather than this view. If ClickHouse is unreachable, or the rollup tables have not been migrated on this deployment, the procedure catches the error and returns the zero-valued empty payload. The screen shows the quiet empty state rather than an error banner, matching the other observability procedures. The source field is always real; there is no synthetic or sampled mode behind this screen.

How averages and peaks are computed

Everything is derived from the bucket series, in the procedure, not in ClickHouse. Window length. The denominator is the number of buckets actually present in the result, times 60 seconds, with a floor of 60 seconds:
The nominal windowMinutes is deliberately not used. If you ask for 24 hours but the org only carried traffic for 3 minutes, the average is computed over those 3 minutes. This keeps “Avg b/w” honest for bursty tenants, but it also means the average is not comparable to a bytes_total / windowMinutes figure you compute yourself, and widening the window does not necessarily lower the average. Average bandwidth, both the KPI and the per-modality column:
Note this is total throughput — ingress and egress summed — in decimal megabits per second, rounded to three decimals for the KPI. Peak bandwidth is the busiest single 1-minute bucket, summed across all modalities, expressed as a rate over its own 60 seconds:
So “Peak b/w” is a 1-minute average at the busiest minute, not an instantaneous line rate. Sub-minute bursts are invisible to it by construction. There is no per-modality peak in the payload; peak is a window-level KPI only. Units. The two families of numbers use different multipliers, which is easy to misread when comparing them. Byte totals are formatted with binary multiples (1024) but conventional KB / MB / GB / TB labels. Bandwidth is decimal megabits (* 8 / 1e6). The throughput chart plots bytes / 60 / 1024 and labels the axis KB/s, so that chart is kibibytes per second while the KPI beside it is decimal megabits per second.

Sessions are peak concurrency, not volume

The sessions column is the most commonly misread number on the screen. Within a modality, sessions is the maximum across the buckets in the window, not the sum. On the QUIC side each bucket’s value is a count of distinct connection subjects active in that minute. So a modality’s session figure answers “what was the highest number of concurrent connections seen in any single minute of this window”, not “how many sessions occurred”. The KPI card then sums those per-modality maxima to produce the sessions figure shown under the Modalities card. That total is a sum of peaks taken independently per modality, so the peaks need not have occurred in the same minute. Practical consequences:
  • Widening the window can only raise a modality’s session count, never lower it, because more buckets can only raise a maximum.
  • Session counts do not add up over time and must not be used as a call volume, stream count, or connection-attempt count.
  • For “how many calls happened”, use Call Detail Records.

Observed, not enforced

This subsystem measures. It does not gate. The procedure reads two rollup tables and returns arithmetic over them; nothing in the path rejects, shapes, throttles, or bills traffic, and no threshold value exists in it to compare against. The screen states this directly in its empty state: bandwidth is observed, not enforced. Read a number here as “this much moved”, never as “this much is allowed to move”. Any limit that applies to your account comes from somewhere else and is not reflected in this payload.

Reconciling traffic with call detail records

Both this screen and CDRs count bytes, and they will not agree. They are not measuring the same thing. Specific reasons a sum over this screen exceeds a sum over CDRs for the same period:
  • Non-call modalities are included. sip, http, ws, kafka_egress, tunnel, vpn, inference, and the rest have no CDR at all.
  • The same call is counted per transport. voice_rtp, voice (QUIC), webrtc, and turn are separate rows for what a CDR treats as one call.
  • Boundaries differ. A call in flight at the edge of the window contributes only its overlapping buckets here, while its CDR lands whole, later, when the call ends.
Use the traffic screen to understand capacity and transport mix. Use CDRs to attribute bytes to a specific call_sid. Neither is an invoice.

Reading the payload directly

If you consume traffic.overview outside the console:
series[].byModality holds combined ingress + egress per modality, so it cannot be split by direction per modality per bucket. Direction is available window-wide (kpi), per modality (byModality), and per bucket in aggregate (series[].bytesIn / bytesOut) — but not at the intersection of modality and bucket. bucket arrives as a ClickHouse DateTime string. Depending on the server’s date_time_output_format, it is either space-separated with no zone (2026-07-15 12:34:56) or already ISO with a trailing Z. Normalise the space to T and only append Z when no zone marker is present — appending unconditionally produces an invalid date on the ISO form.