The stream detail page in the ClutchCall Stream console is the operational view of a single live input. Alongside the preview player and the ingest/playback endpoints, it renders a four-value QoE snapshot: Viewers, Glass-to-glass, Bitrate and Dropped. This page explains where those numbers come from, how often they move, what a dash means, and what the embed-builder checkboxes actually change in the URL.

The live stats snapshot and its refresh window

Two independent queries feed the top of the page: liveStats returns a single snapshot object per live input — it is not a time series. The values come from a rollup in ClickHouse that the relay mesh feeds; the console just renders the most recent row for this input. Because the console polls on a fixed interval, a value you read can be up to one interval stale. A stream that just went live, or an encoder that just stopped, will not be reflected in the stats until the next poll completes.

What each stat measures

Notes on the rendering, because the displayed value is not always the raw field:
  • Viewers is a point-in-time count of subscribers attached to this playback id right now, not a session total for the broadcast.
  • Glass-to-glass is the median (p50) end-to-end latency across the last five minutes, not the current instantaneous latency of any one viewer. A single badly-connected viewer will not move the p50 much.
  • Bitrate is reported by the API in kbps and divided by 1000 for display, so 4200 renders as 4.2 Mbps. It is the delivered, per-viewer rate — what subscribers are actually receiving — not the rate your encoder claims to be pushing at ingest.
  • Dropped is a percentage over the same five-minute window as glass-to-glass, printed to two decimal places, so small non-zero loss stays visible instead of rounding to 0.
The colours on these tiles are fixed in the layout. They are not a health signal — a green Glass-to-glass tile is green whatever the number is.

Why a stat reads as a dash

A — means “nothing to show”, and there are two different reasons for it:
  • The snapshot has not loaded. If the liveStats query has not resolved (or errored), all four tiles show —, including Viewers.
  • The value is zero-guarded. Glass-to-glass and Bitrate render — rather than 0 when the underlying field is 0, because a zero there means “no measurement yet” rather than “zero milliseconds” or “zero Mbps”. This is normal in the first moments after an encoder connects and before any subscriber has pulled media.
Viewers and Dropped are not zero-guarded: once the snapshot loads, they render 0 and 0.00 honestly. Viewers 0 on a live stream is a real statement — nobody is watching — not a missing measurement.

Reading the numbers when a stream looks wrong

The four values split cleanly into an ingest side and a delivery side, which is what makes them useful together:
  • Viewers 0, but the badge says LIVE. Ingest is fine; the relay is accepting your publish. The problem is on the playback side — wrong playback id in the player, or a signed-playback policy rejecting subscribers. Check the playback id and signed URL in the Setup tab before touching the encoder.
  • Dropped climbing while Bitrate falls. Delivered bitrate is what viewers receive, so these two moving together points at the path between the relay and subscribers, or at a publisher uplink that can no longer sustain the encode. Compare against what your encoder reports it is sending.
  • Dropped climbing while Bitrate holds. Media is still flowing at rate but packets are being lost. Treat it as a network-path problem rather than a capacity one.
  • Glass-to-glass rising with Viewers and Bitrate steady. Latency is accumulating somewhere in delivery. The edge serving this input is printed in the page subtitle as edge <relay_region> — note it before you escalate, since a regional edge is the usual explanation for a latency shift that no other signal reflects.
  • All four dashed while the badge says LIVE. The liveStats query is the thing that is failing, not the stream. The live-input record and the stats snapshot are separate queries; one can fail while the other succeeds.
For industry-standard definitions and healthy ranges of the underlying quality metrics, see Telephony Metrics. For the raw metric and trace streams behind the rollups, see Telemetry.

Live and offline states

The page treats an input as live when any of these hold: is_live is true, or status is active, or status is recording. That drives three things at once — the LIVE/OFFLINE badge, whether the hosted preview iframe is mounted, and whether the LIVE EDGE indicator appears under the player. When the input is offline the preview is replaced by a placeholder that prints two facts worth reading:
  • first seen <timestamp> from first_seen_at, or not yet ingested if the input has never received media. “Not yet ingested” on an input you believe is configured means the encoder has never successfully reached the relay — check the key, not the player.
  • recording on / recording off from recording_enabled, so you can tell before the fact whether this session will produce a VOD asset.
The preview iframe loads the same hosted embed route that viewers get (/api/streams/embed/<playback-id>), so if the preview plays, the public embed plays.

Embed URL parameters

The Embed tab builds an <iframe> snippet live from four checkboxes. Each checkbox appends one query parameter to the embed URL; unchecked options are omitted entirely rather than sent as =0. The base URL is:
The default state in the console is Low-latency and Autoplay on, Signed URL only and Show viewer count off, producing:
The parameters compose in the order listed above, and the first one present takes the ?. Copying the snippet with the copy button gives you exactly what the preview pane shows.

Signed playback URLs

The unsigned MoQ subscribe URL, moq://relay.clutchcall.dev/playback/<external_input_id>, is not authenticated — any client that knows or guesses the input id can subscribe. Generate signed playback URL in the Setup tab calls streams.liveInputs.mintPlaybackToken with a TTL of 3600 seconds and mints an Ed25519 JWT against your org’s active playback signing key. The mutation returns the input id, the token, and expires_at. The console composes them into:
and shows the expiry time next to the field. On the relay, mod_streams verifies the tok= claim against the public half of the signing key cached in Redis before it allows the SUBSCRIBE. Key lifecycle and rotation are covered in Authentication.

Recordings from this live input

The Recordings tab lists VOD assets produced by this live input. The console fetches the org’s assets with streams.assets.list and filters client-side on source_live_input_id matching the current input id; the resulting count is the number badged on the tab. Whether a session produces an asset at all depends on the input’s recording_enabled flag, which the offline placeholder prints. Two consequences of the list being polled at its own 60 s interval and filtered client-side:
  • A recording that has just been produced can lag the live stats by up to a minute before it appears in the tab.
  • The tab reflects the first page of assets the list procedure returns, so a very large asset library can outrun what is shown here.
Deleting the live input does not delete its recordings. The confirmation dialog states the behaviour plainly: the input row is soft-deleted, any recording assets remain on file, and active encoders are disconnected.

Resetting the stream key

Reset stream key calls streams.liveInputs.resetKey and is immediate and disruptive: any encoder still using the previous key starts failing as soon as the mutation lands. The new key is returned in cleartext exactly once, in a dialog, and is never retrievable afterwards — the detail page and the list only ever render stream_key_preview. Copy it into your encoder config before dismissing the dialog.