An FFmpeg process can remain visible in your process list while its input, output connection, or local machine has stopped making useful progress. A practical health check therefore needs to watch both FFmpeg itself and YouTube's view of the incoming stream.
Use FFmpeg's program-friendly progress output to detect an exit or likely local stall, then query YouTube's Live Streaming API for stream status and health details. These checks complement one another, but neither one alone can prove that viewers are receiving a healthy broadcast.
What a health check can detect
A health check is a set of observations, not a guarantee. It can tell you that FFmpeg exited, that its progress records have stopped arriving, or that YouTube is reporting an inactive stream or a health issue. It cannot prove that every viewer has a good picture and sound, and it cannot make YouTube accept a stream that has the wrong settings.
For an always-on devotional loop, study channel or local news stream, begin by writing down the failures you want to notice. They may include:
- FFmpeg exits because an input file cannot be opened, the process receives a termination signal, or the output connection fails.
- FFmpeg remains alive but stops producing progress records.
- FFmpeg continues producing progress records while its connection to YouTube is unusable.
- YouTube receives data but reports an inactive stream, a configuration problem or poor stream health.
- YouTube reports active and healthy status while the actual preview has missing audio, a frozen picture or another viewer-facing problem.
The distinction matters because the response differs. A dead process may need restarting. A local stall may require checking the input disk, source file or machine load. A YouTube-reported issue may point towards bitrate, frame rate, keyframe interval, codec, authentication or ingest configuration instead.
Do not turn one signal into a diagnosis it cannot support. “FFmpeg is running” is not the same as “YouTube is receiving a healthy stream”, and “YouTube reports active” is not the same as “the viewer experience is good”.
Use two monitoring layers
The first layer runs beside FFmpeg and watches the local process. It has direct access to the process identifier, exit code, progress stream and local diagnostic log. It can answer, with reasonable confidence, whether FFmpeg is still executing and whether it is emitting new progress information.
The second layer asks YouTube about the stream associated with the broadcast. It depends on an authorised YouTube API request and on the relevant stream and broadcast identifiers. It can report what YouTube says about receipt of data and stream health, rather than what FFmpeg believes it has sent.
| Layer | What it observes | Useful failure signal | Main dependency | What it cannot prove |
|---|---|---|---|---|
| Local process check | FFmpeg process and exit status | Unexpected exit | Access to the local process | That YouTube is receiving data |
| Local progress check | New -progress records |
No progress beyond your chosen threshold | Correctly routed progress output | That the output is reaching viewers |
| YouTube API check | streamStatus, healthStatus and issue details |
Inactive, error or reported health problem | OAuth access and API availability | That every viewer has good picture and sound |
| Monitor preview | Incoming picture and sound as seen in YouTube's interface | Visible or audible quality problem | Human review | Continuous automated coverage |
YouTube describes status.streamStatus as the state of the stream connection. Its value active indicates that YouTube is receiving data from the encoder. Health is a separate question. The API's health status can be good, ok, bad or noData; noData means that YouTube has no health information available, not that the stream is healthy.
The FFmpeg and OBS choice for a 24/7 study stream is useful background if you are still deciding which encoder to supervise. This article assumes that FFmpeg is already the process producing the YouTube output.
Capture FFmpeg exit status and progress
FFmpeg offers the -progress option for program-friendly progress output. That is preferable to making a monitor parse the changing, human-oriented status line normally printed during encoding. Send progress to a pipe, a FIFO, or another destination that your supervisor can read one record at a time.
A simplified command might look like this:
ffmpeg \
-re -stream_loop -1 -i loop.mp4 \
-c:v libx264 -c:a aac \
-f flv "rtmps://example-ingest-endpoint/app/STREAM_KEY" \
-progress pipe:1 \
-stats_period 1 \
2>ffmpeg-stderr.log
Treat the endpoint and stream key in that example as placeholders. Do not copy a stream key into a shared script, ticket or alert. The output URL can expose the key, so avoid printing the fully expanded command in general-purpose logs.
The FFmpeg documentation describes -stats_period as the interval used for progress and statistics updates, with a default of 0.5 seconds. That is an output cadence, not a universal health-check timeout. You might choose a different value so that the monitor has enough information without creating unnecessary processing or log volume. Read the FFmpeg command-line documentation for the exact behaviour of the options used by your installed version.
Your watcher should record at least three facts:
- The time of the most recent valid progress record.
- The latest
out_time,frame,fpsor other fields that are meaningful for your job. - FFmpeg's final exit code when the process ends.
A progress record commonly ends with a line such as progress=continue and eventually a final state such as progress=end. Do not rely on a single field without checking the format produced by your FFmpeg build. The key point is to update a last-seen timestamp whenever a complete, recognisable progress record arrives.
A minimal supervision pattern is:
start FFmpeg
start a reader for -progress output
start a reader for stderr
while FFmpeg is running:
if a complete progress record arrives:
save its timestamp and selected fields
if current time - last progress time exceeds stall threshold:
raise a local-stall alert
when FFmpeg exits:
save the exit code
raise an exit alert unless this was an intentional stop
The supervisor should distinguish an intentional shutdown from an unexpected exit. If an operator is changing a stream key or replacing a file, suppressing an alert during the planned maintenance window prevents a normal action from looking like a failure. When the process exits unexpectedly, preserve the exit status and the last progress record in the alert.
Keep diagnostic logs separate
Progress is for supervision. FFmpeg's diagnostic output is for investigation. Keep those channels separate so that a verbose warning, reconnect message or codec detail cannot be mistaken for a progress heartbeat.
Direct stderr to a rotating diagnostic file, while sending -progress to the monitor. Keep timestamps in both records, ideally using the same clock and a consistent time zone. If your wrapper adds its own messages, prefix them clearly so you can tell which lines came from FFmpeg and which came from the supervisor.
A useful incident bundle contains:
- The start time and exact input file or source name.
- The FFmpeg command with the stream key removed or masked.
- The last several progress records.
- The process exit code, signal or wrapper result.
- The diagnostic log covering the failure window.
- The latest YouTube API status and configuration issues.
- Whether a person checked the YouTube monitor preview.
Use log rotation and retention suitable for the disk on the machine running the stream. An always-on channel can generate a large diagnostic file if warnings repeat all night. Rotation prevents a monitor from creating a second outage by filling the disk, but do not discard the short period around an incident before it has been collected.
Do not build the monitor around text such as “frame=” or “speed=”. Those fields are useful to a person reading a log, but their wording and formatting are less suitable as a machine interface. Use -progress for the heartbeat and retain stderr for context.
If your output uses RTMPS, check the secure endpoint, hostname and port as part of setup. YouTube's RTMPS guidance states that the connection must use port 443 on the ingestion server. A wrong hostname can also affect TLS server-name indication, while attempting cleartext RTMP against an RTMPS endpoint can result in connection or timeout errors. These checks explain some failures, but they do not replace YouTube-side status monitoring.
Choose a stall threshold and alert policy
There is no single correct stall threshold for every channel. Choose it from the behaviour of your input and the delay your operator can tolerate. A file loop with regular output may produce progress frequently. A capture or network input may have legitimate pauses. Your threshold must be longer than an expected quiet period, while still short enough to be useful for the channel.
Do not use FFmpeg's 0.5-second default statistics interval as the alert threshold. It only describes the default interval between progress and statistics updates. If you set an alert immediately after one missed record, a brief scheduling delay or busy disk could create false alarms.
Choose three values deliberately:
- The progress output interval, controlled by your FFmpeg invocation.
- The local stall timeout, after which you report a likely local problem.
- The number of consecutive failed remote checks, or the persistence period, before alerting on a YouTube status change.
The last item is alert hysteresis. For example, your monitor might require the same concerning state to persist across more than one poll before notifying a person, then require a healthy state to persist before sending a recovery message. The actual polling interval and persistence rule should match your channel's latency, connectivity and staffing. The official documentation does not establish one generally recommended interval for this method.
Label the alert according to what is known:
| Observed condition | Suggested wording | Immediate next check |
|---|---|---|
| Process ended unexpectedly | “FFmpeg exited; local stream process is down” | Exit code and stderr |
| Process alive, progress stale | “FFmpeg progress stale; probable local stall” | Input, disk, CPU and wrapper |
| Progress continues, YouTube inactive | “Local progress continues; YouTube reports inactive” | Output URL, key, network and API state |
| Progress continues, YouTube health bad | “YouTube reports a health issue” | Returned issue type, severity and description |
YouTube noData |
“YouTube health data unavailable” | Retry and inspect stream lifecycle |
| API healthy, preview poor | “Machine status healthy; manual quality check needed” | Picture and sound in monitor preview |
This wording avoids claiming more than the evidence supports. A “probable local stall” is more honest than a statement that the encoder has definitely failed, especially when the reader process itself might be blocked or the machine clock has changed.
Rate-limit notifications separately from detection. One stalled loop should not send a new message every second. Record every state transition locally, but notify only on a transition, after the chosen persistence period, and when the state recovers.
Query YouTube's stream health
The YouTube Live Streaming API gives you the remote layer. Identify the broadcast and the live stream bound to it, then request the stream resource and collect the status fields. The relevant data includes status.streamStatus, status.healthStatus.status and status.healthStatus.configurationIssues.
The YouTube Live Streaming API stream documentation explains how to retrieve stream resources. Your monitor should preserve the complete issue type, severity, reason and description returned by YouTube, rather than reducing every problem to “bad”. An issue such as video ingestion starvation has a different investigation path from an audio setting mismatch or an unsupported codec.
YouTube's description of video ingestion starvation is direct: “YouTube is not receiving enough video to maintain smooth streaming. As such, viewers will experience buffering.” That message is more useful in an alert than a locally inferred statement that FFmpeg is slow, because it records what YouTube has observed.
A remote check might follow this pattern:
request the stream resource using authorised credentials
read status.streamStatus
read status.healthStatus.status
for each configuration issue:
retain type, severity, reason and description
write a timestamped result
Treat API errors as a separate monitor state. An expired token, temporary API failure or unavailable network does not mean that YouTube has reported a bad stream. Say “remote health check unavailable” and keep the local process and progress checks running.
YouTube Live API access requires OAuth 2.0. The YouTube authentication guide explains the authorisation flow, and YouTube Live does not support service-account flow for this purpose. Protect access and refresh tokens in a credential store. Do not put bearer tokens in URLs or write them to the same logs that operators routinely share.
The remote layer is especially valuable when local progress continues. FFmpeg may be encoding frames and attempting to send them while the wrong stream key, endpoint, port, TLS setup or stream configuration prevents a useful ingest. YouTube's response cannot identify every local cause, but it can stop you from treating a running process as proof of a working broadcast.
Check YouTube Live Control Room
The API is suitable for automation, but a person should still inspect YouTube's monitor preview when the channel matters. A machine can report active ingest while the wrong file is playing, audio is silent, the picture is frozen in a way not captured by the chosen signal, or the visible result is not what you intended to publish.
YouTube's broadcast lifecycle guidance says to confirm that the bound stream's status.streamStatus is active before moving through the broadcast workflow. It also describes using a monitor stream to inspect the incoming feed. Use that preview to verify picture and sound, and record whether the check was automated or human.
This is particularly important for channels that run unattended overnight. A person may not be available for every alert, so the script should state what it knows and what it has not checked. “YouTube API active; preview not checked” is a useful operational record. “Stream healthy” may be too broad if no one has verified audio and picture.
If a music or devotional channel has intermittent sound, keep a separate runbook for that symptom. The article on a yoga music livestream losing audio on YouTube in India covers a viewer-facing audio investigation rather than replacing the health script.
Test failure and recovery behaviour
Do not wait for a real overnight outage to find out whether your monitor works. Test each layer deliberately in a short, controlled window and document what the operator should see.
First, stop FFmpeg cleanly and confirm that an intentional stop is not treated as an incident. Then terminate it unexpectedly and verify that the wrapper records the exit code, retains the final diagnostic lines and sends one useful alert. Start it again and check that the recovery message identifies the new process and does not rely on stale progress from the previous run.
Next, create a local progress-stall test. The safest method depends on your wrapper and input, but the purpose is to stop or block the progress reader without pretending that YouTube has failed. Confirm that the monitor says “progress stale” or an equivalent local diagnosis, not “YouTube offline”. Also test a delayed progress record so you can see whether the chosen threshold creates false alerts.
Test the remote layer independently. Use an authorised request for the intended stream, then simulate an unavailable API response or expired credential in a test environment. The monitor should distinguish “remote check unavailable” from a returned bad health status. Restore credentials and confirm that the state recovers without restarting FFmpeg.
Finally, validate the output configuration against the current official YouTube guidance. Check the stream key, ingestion protocol, endpoint, port, codec, bitrate, frame rate and keyframe interval. If the key changes, follow a runbook such as recovering a YouTube radio livestream after a stream key change, then verify both local progress and YouTube status.
A good recovery policy should not blindly restart forever. Limit repeated restarts, retain the reason for each attempt and escalate when the same failure returns. A restart may help after a process exit, but it will not correct an invalid stream key, unsupported setting, missing OAuth permission or a network route that remains unavailable.
Put the checks into an operating routine
Keep the local supervisor, API poller and human runbook as separate concerns even if one program presents their results together. This makes it easier to tell whether an alert came from a dead process, stale progress, unavailable API data or a YouTube-reported issue.
At the start of a broadcast, record the broadcast and stream identifiers, the input file or source, the FFmpeg version, the selected progress interval and the operator-chosen stall threshold. Mask secrets in every stored command. During operation, retain state transitions rather than only the latest green status.
For a small channel, a single script and a clear alert destination may be enough. A larger operation may want a process supervisor, structured logs and a dashboard. The principle remains the same: use FFmpeg's progress as evidence about local execution, use YouTube's API as evidence about the remote service, and use the monitor preview for a human quality check.
If the main reason for monitoring is to avoid leaving a home computer running overnight, StreamNeo removes that particular operational burden by letting you upload the video, provide the YouTube stream key and have the broadcast run with automatic monitoring and restart handling, without installing software locally. It remains a YouTube-only option, so YouTube's own status and policy checks still matter.
Before committing, compare the operating options on the pricing page. When the file and channel are ready, start free — 24-hour trial, no card.
FAQ
Can FFmpeg being alive prove that YouTube is receiving the stream?
No. It only shows that the local process has not exited, and progress output shows that FFmpeg is still reporting work. You need YouTube's reported stream status and health fields for a remote signal, plus the monitor preview when picture and sound matter.
Should I alert as soon as one FFmpeg progress record is late?
Usually not. Set the progress interval and stall threshold for your input and operating conditions, then use persistence or hysteresis to reduce false alerts. FFmpeg's documented default statistics interval is not a universal failure threshold.
What should I do with YouTube's noData health status?
Treat it as unavailable or not-yet-reported health information. Retry according to your operating policy and report the state separately from bad, because noData does not prove that the stream is healthy or unhealthy.
Can the script restart FFmpeg automatically?
It can be designed to restart after a confirmed local exit, but recovery is not guaranteed. Limit repeated attempts, preserve the exit and diagnostic information, and investigate YouTube configuration, authentication and network errors that a restart cannot fix.