# Monitoring a live input

> Read the live QoE snapshot on a stream's detail page, interpret viewers, glass-to-glass, bitrate and dropped, and understand embed URL options and recording assets.

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:

| Query | Procedure | Refetch interval |
| ----- | --------- | ---------------- |
| Live input record (name, status, `relay_region`, `stream_key_preview`, `recording_enabled`) | `streams.liveInputs.get` | 10 s |
| QoE snapshot (the four mini-stats) | `streams.liveInputs.liveStats` | 10 s |
| Recording assets (drives the Recordings tab count) | `streams.assets.list` | 60 s |

`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

| Stat | Field | Unit rendered | Window shown in the console |
| ---- | ----- | ------------- | --------------------------- |
| Viewers | `viewers_now` | count, locale-formatted | concurrent now |
| Glass-to-glass | `g2g_p50_ms` | ms | p50, last 5 min |
| Bitrate | `bitrate_kbps` | Mbps, one decimal | delivered, per viewer |
| Dropped | `dropped_pct` | %, two decimals | last 5 min |

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](/glossary/metrics). For the raw metric and
trace streams behind the rollups, see [Telemetry](/platform/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:

```
https://streams.clutchcall.dev/api/streams/embed/<external_input_id>
```

| Console option | Parameter appended | Effect |
| -------------- | ------------------ | ------ |
| Low-latency (MoQ) | `lowLatency=1` | Plays over the low-latency MoQ path. |
| Autoplay (muted) | `autoplay=1` | Starts playback automatically, muted. |
| Signed URL only | `signed=1` | Embed honours the signed-playback policy — playback requires a token. |
| Show viewer count | `viewers=1` | Renders the concurrent viewer count in the player chrome. |

The default state in the console is Low-latency and Autoplay on, Signed URL
only and Show viewer count off, producing:

```html
<iframe src="https://streams.clutchcall.dev/api/streams/embed/<external_input_id>?lowLatency=1&autoplay=1"
  width="640" height="360" frameborder="0"
  allow="autoplay; fullscreen; picture-in-picture"
  allowfullscreen></iframe>
```

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:

```
moq://relay.clutchcall.dev/playback/<input>?tok=<token>
```

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](/concepts/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.

## Related

- [Telemetry](/platform/telemetry) — metrics, traces and the rollup stores
- [Telephony Metrics](/glossary/metrics) — definitions and healthy ranges
- [Authentication](/concepts/authentication) — signing keys and token rotation
