# Live input states and health signals

> What active, idle, and errored mean on a live input, and how to read the viewer, egress, and glass-to-glass columns in the live streams table.

A **live input** is a persistent ingest endpoint that an encoder publishes
to. ClutchCall reserves it for your org, so the same stream key and
playback URL survive across broadcasts. The input therefore exists whether
or not anything is currently publishing to it — which is why it carries a
status.

This page explains the status values the console shows, the per-input
health numbers next to them, and the order to check them in when a
broadcast does not come up.

## Where the live streams table gets its data

The table is backed by a single procedure:

```ts
trpc.streams.liveInputs.list({ orgId, page, perPage })
```

It joins the Postgres `stream_live_input` table with live viewer counts
from the ClickHouse `stream_viewer_latest` table and returns one row per
input:

| Field                | Column in the console | Notes                                                    |
| -------------------- | --------------------- | -------------------------------------------------------- |
| `id`                 | Live input (subtitle) | Stable identifier. Row click opens `/live/<id>`.          |
| `name`               | Live input            |                                                           |
| `status`             | Status                | `active`, `idle`, or `errored`.                           |
| `relay_region`       | Edge relay            | `auto` renders as `—`.                                    |
| `recording_enabled`  | Protocol (`REC` tag)  | Boolean flag on the input.                                |
| `viewers_now`        | Viewers               | From `stream_viewer_latest`.                              |
| `bytes_egress_now`   | Egress · 1m           | Bytes; the console renders MB.                            |
| `g2g_p50_ms`         | Glass-to-glass        | Median glass-to-glass latency, in milliseconds.           |
| `stream_key_preview` | (searchable only)     | Truncated key, matched by the search box.                 |

The ingest protocol tag on every row is `MoQ`.

The query refetches every 30 seconds, so the numbers in the table are a
periodic snapshot rather than a live tick. Reload or wait for the next
refetch before concluding that a value has not moved.

## Live input status values

The status column has three values, and the Status filter chip cycles
through exactly those plus `any`:

| Status    | What the row looks like                                                                 |
| --------- | --------------------------------------------------------------------------------------- |
| `active`  | Counted in the **Active now** KPI. Viewer, egress, and glass-to-glass figures are populated for a publishing input. |
| `idle`    | The input exists and holds its stream key and playback URL, but is not in the active count. Viewers and egress render as `—` when they are zero. |
| `errored` | Counted in the **Errored** KPI, which turns red as soon as the count is above zero. Filter the table to `errored` to isolate these rows. |

Status is served by the control plane on the list row — the console does
not derive it from the viewer or egress figures. An input that shows
`active` with no viewers is a publishing input nobody is watching; an
input that shows `idle` is one nothing is currently publishing to.

Because the input is persistent, deleting it is not part of recovering
from `errored` or `idle`. The stream key and playback URL are meant to
outlive individual broadcasts.

## Reading viewers, egress, and glass-to-glass

These three columns are per-input and independent of status.

**Viewers** is `viewers_now`, the current concurrent viewer count joined
in from ClickHouse. Zero renders as a dimmed `—` rather than `0`, so a
column of dashes means nobody is subscribed — not that the data is
missing. The **Concurrent viewers** KPI is the sum of this column.

**Egress · 1m** is `bytes_egress_now`, rendered in MB to one decimal
place. It is the recent egress figure for that input, so it scales with
both bitrate and viewer count. Zero renders as `—`. An input that is
`active` with viewers but no egress is the signature of a delivery
problem rather than an ingest problem.

**Glass-to-glass** is `g2g_p50_ms`, the median end-to-end latency for
that input in milliseconds — capture to display, not just relay transit.
It is a p50, so a small number of badly-served viewers will not move it.

## Recording on and off

`recording_enabled` is a flag stored on the live input, not a per-broadcast
setting. When it is on, the row carries a blue `REC` tag next to the
protocol tag, and the input is counted in the **Recording** KPI card.

You can change it for one input or many at once. Select rows and use
**Start recording** / **Stop recording** in the bulk bar; each selected
input gets an

```ts
trpc.streams.liveInputs.update({ orgId, id, recording_enabled })
```

call, and the table invalidates and refetches when they all settle. The
**Recording** filter chip (`all` / `on` / `off`) narrows the table to one
side of the flag, which is the quickest way to confirm a bulk change
landed on everything you selected.

## Rotating a stream key

**Reset key** in the bulk bar calls:

```ts
trpc.streams.liveInputs.resetKey({ orgId, id })
```

once per selected input. This is destructive and the console confirms
first: any encoder still using the old key is rejected on its next
connect and has to be reconfigured. A running broadcast is therefore
fine until the encoder reconnects — which is exactly when you find out
whether the new key reached it.

The search box matches against `stream_key_preview` as well as name and
id, so you can paste the leading characters of a key an encoder is
configured with and find the input that owns it.

## Filtering and searching the inputs table

All filters run client-side over the inputs loaded on the current page:

- **Search** — substring match over name, id, and stream key preview.
- **Status** — cycles `any` → `active` → `idle` → `errored`.
- **Region** — cycles `all` and then each distinct `relay_region` present
  on the loaded rows. Inputs set to `auto` are not offered as a region
  value.
- **Recording** — `all` / `on` / `off`.
- **Tags** — matches tags on the `stream_live_input` resource, including
  **inherited** tags. A filter on an org-level tag such as `env=prod`
  therefore also matches inputs that never had the tag set directly.

The counter at the right of the filter bar shows how many inputs survive
the filters out of how many are loaded.

## Why the KPI cards say "on this page"

The table pages at 100 inputs per request. The **Active now**,
**Concurrent viewers**, **Errored**, and **Recording** KPIs are computed
from the rows that are currently loaded, not from a separate org-wide
aggregate — so when the org has more inputs than fit on one page, each of
those cards is annotated *on this page*. Only **Inputs total** is the
org-wide number, taken from `total` on the response.

If you see that annotation, page through the table or narrow with filters
before treating a KPI as an org-level count.

## Triage order when a broadcast does not come up

Work down the row, left to right — each column rules out a layer.

1. **Find the input.** Search by name, id, or the leading characters of
   the stream key the encoder is configured with. If the key prefix does
   not match any input, the encoder is pointed at a key that no longer
   exists — most often because it was reset.
2. **Read the status.** `idle` means nothing is publishing: the problem
   is at the encoder or its credentials. `errored` means the input itself
   is in a failure state; filter the table to `errored` and open the
   input for its detail view. `active` moves you to step 4.
3. **If `idle`, check the key.** Confirm the encoder's key matches
   `stream_key_preview`. If it was rotated, reconfigure the encoder — a
   further reset will not help.
4. **If `active` but Viewers is `—`.** Ingest is working and nobody is
   subscribed. Check the player and the playback URL, not the encoder.
5. **If Viewers is non-zero but Egress · 1m is `—`.** Subscribers are
   attached and no bytes are leaving. This is a delivery-side problem;
   note the **Edge relay** region before escalating.
6. **If everything is populated but playback is poor.** Read
   **Glass-to-glass**. It is a p50, so compare it against the same
   input's usual value and against other inputs on the same edge relay
   region rather than reading it in isolation.

Remember the 30-second refetch at every step: give the table one refresh
cycle after any encoder or recording change before re-reading the row.

## Related

- [Streams cookbook](/modalities/streams/cookbook) — example publisher and viewer apps
- [Authentication](/concepts/authentication) — minting playback tokens for viewers
- [Telemetry](/platform/telemetry) — the metric and trace streams behind these numbers
