Skip to content
streamneo.
Streaming Settings13 min read

How to Add a Scrolling Text Ticker to a Continuous FFmpeg YouTube Stream

Build an FFmpeg scrolling ticker, refresh its text safely, and test the overlay separately from YouTube Live delivery.

sn.
StreamNeoPublished 4 October 2026
Worth sharing?

A scrolling ticker on a continuous FFmpeg stream is made with FFmpeg’s drawtext filter, not with a YouTube setting. The filter changes the video pixels before encoding, while YouTube’s settings control how that encoded stream reaches the platform.

You can use fixed text or read the message from a UTF-8 file that is refreshed while FFmpeg continues running. Build and test the overlay separately first, then connect the finished command to YouTube Live and monitor both rendering and delivery.

How FFmpeg drawtext creates a ticker

The drawtext filter places text over each video frame. FFmpeg’s documentation describes it as drawing text, or text from a specified file, on top of video using the libfreetype library. That means the ticker is part of the rendered picture: viewers receive it as pixels in the video rather than as a separate YouTube layer.

A simple fixed message might look like this inside a filter chain:

drawtext=fontfile=/path/to/font.ttf:text='Now playing':fontsize=32:fontcolor=white:x=40:y=h-48

The exact syntax depends on your shell, FFmpeg build, font path and output dimensions. Do not assume that a command copied from another machine will work unchanged. First check the FFmpeg version and whether the installed build includes the required text-rendering support. Then confirm that the font file exists and can be read by the account running FFmpeg.

A ticker normally has two parts. A drawbox creates a contrasting strip, and drawtext puts the moving copy on top of it:

drawbox=x=0:y=h-64:w=w:h=64:[email protected]:t=fill,
drawtext=fontfile=/path/to/font.ttf:text='Now playing':fontsize=32:fontcolor=white:y=h-48:x=w-mod(t*180\,w+text_w)

This is an illustrative filter fragment, not a complete tested streaming command. The band is 64 pixels high in this example, and the text size and speed are starting values to inspect at your target resolution. A ticker that looks comfortable on a 1080p preview may be too small on a phone, while a band designed for a vertical crop may cover important artwork in a landscape stream.

The filter causes video re-encoding because it changes the image. You cannot add this overlay while copying the existing video stream unchanged. Audio can usually be mapped separately, but you must explicitly choose suitable audio and video settings for the machine and the YouTube configuration.

Choose the ticker text and position

Decide what the ticker is for before choosing its movement. A devotional channel might show the current chant, language or schedule. A local news loop might show a short headline and time. A small business may need opening hours or a contact method. Keep the message useful when it is seen halfway through its journey, because a viewer can join the live stream at any point.

The bottom edge is common because it leaves the centre of the picture available. It is not automatically the right position. Check whether subtitles, lower-thirds, faces, song titles or important artwork already occupy that area. For a study channel, a ticker across the bottom can cover equations or notes. For an ambience stream, a narrow, low-contrast strip may be less distracting than a large opaque banner.

The x and y options accept expressions. In the example, y=h-48 places the text baseline area near the bottom of the frame, while the box begins at h-64. Those values are tied to the example band and font size, so adjust them together rather than treating them as universal settings.

Useful checks include:

Decision What to check Typical consequence
Band height Does the background cover the full text without touching it? Too little space clips or crowds the letters
Font size Can the message be read in the YouTube preview and on a phone? Larger text needs more horizontal travel
Contrast Does white text remain clear over changing video? A translucent or solid box may be needed
Position Does it avoid subtitles and key artwork? Moving the band can preserve the main content
Message length Can a viewer understand it while it passes? Long copy takes longer to leave the screen

Use a real sample from the planned channel rather than placeholder text alone. Hindi, Sanskrit and other scripts can expose font coverage problems that plain English does not. If a font lacks a glyph, the output may show a missing-character box or an unexpected substitute. Test the languages, punctuation and symbols that the unattended stream will actually use.

A ticker does not improve stream delivery, discoverability or approval. It only adds information to the picture. If the source video stops, the network drops or YouTube reports an ingest problem, the ticker does not repair that underlying issue.

Animate x across the frame

For a left-moving ticker, start the text just beyond the right edge and reduce its x position over time. The basic idea is linear movement: frame width minus elapsed time multiplied by a chosen speed. The text keeps travelling until its right edge has passed beyond the left side.

One practical expression is:

x=w-mod(t*180\,w+text_w)

Here, t represents elapsed time in seconds, 180 is an example movement rate, w is the video width and text_w is the rendered text width. The mod operation wraps the text back to the right after it has crossed the left side, producing a repeating ticker.

Treat the speed as a value to tune, not as a standard recommendation. If it moves too quickly, viewers cannot read it. If it moves too slowly, a long period may pass before the complete message appears. The correct choice depends on character count, language, font, frame size and the attention you expect from viewers.

A wrapped expression can produce an awkward join. The same message may return as soon as its last characters leave, with little or no empty space. If you want a deliberate gap, include spacing in the text or design a longer movement period. The expression must account for the rendered width, and the exact behaviour should be checked against the FFmpeg version installed on your host.

Expressions are also where quoting problems become common. Commas can separate filter options, colons divide option names from values, and shell characters may be interpreted before FFmpeg receives them. In a shell command, the comma in an expression often needs escaping, as shown with \, in the fragment. A different shell or operating system may require different escaping.

Build the filter in stages. First render a static message. Then test the movement with a short local output. Only after that should you add file reloading and the YouTube output. This makes it easier to tell whether a failure comes from a font path, a filter expression, shell quoting or the ingest connection.

Load changing text from a UTF-8 file

For a fixed message, text= is direct. For a channel whose announcement changes, textfile= is easier to maintain because the copy lives outside the long FFmpeg command. The file should be saved as UTF-8, and the selected font must support the characters you put in it.

A filter fragment using a file can look like this:

drawbox=x=0:y=h-64:w=w:h=64:[email protected]:t=fill,
drawtext=fontfile=/path/to/font.ttf:textfile=/path/to/ticker.txt:reload=1:fontsize=32:fontcolor=white:y=h-48:x=w-mod(t*180\,w+text_w)

The file might contain one short line such as:

Next session begins at 18:00 | Subscribe for the evening programme

The file is not a control channel for YouTube. It is input to the local video filter. When FFmpeg reads new text, it renders that text into subsequent frames according to the filter’s reload behaviour. The change is not necessarily visible at the instant another process saves the file, and a viewer may still see buffered frames.

A file also avoids some command-line escaping, but it does not eliminate all operational concerns. The path must be readable, the encoding must be correct and the file must remain available for the entire run. Keep the path simple while testing. Once the basic version works, add the copy-management process.

Compare the two approaches before choosing one:

Text source Best for Main risk Maintenance pattern
text= A message that rarely changes Shell quoting becomes difficult with punctuation Restart or replace the command when copy changes
textfile= with reload= Announcements edited during a long run A bad update or partial read can affect the displayed text Write a complete replacement and swap it into place

Use the file method when the operator needs to update a schedule, headline or programme label without rebuilding the entire stream command. If the copy changes only once a week, the simpler inline form may be easier to audit.

Set reload behaviour and update the file safely

reload tells drawtext to reread the text file at a frame interval. A setting such as reload=1 asks FFmpeg to check it frequently, but it does not mean the update is instantaneous. The filter still processes frames, the operating system still handles file visibility, and the player may buffer the live output.

The important safety rule is to avoid writing directly into the file that FFmpeg is reading. A writer could truncate the file, write only half a sentence or leave a temporary encoding state visible during a reload. FFmpeg’s filter documentation warns that a reloaded text file should be updated atomically to prevent partial reads.

A safer workflow is:

  1. Create the new content in a temporary file in the same directory.
  2. Write the complete UTF-8 text and close the file.
  3. Replace the old ticker file with the completed file using an atomic rename operation supported by the operating system.
  4. Leave the replacement at the exact path used by FFmpeg.
  5. Watch the local output and logs for the next few reload cycles.

The same-directory detail matters because a rename within one filesystem is generally the operation you want for a clean replacement. The exact command differs between Linux, macOS and Windows, so use the documentation for the environment running FFmpeg. Do not make a cross-device copy-and-delete sequence your update method without understanding what the reader can see between those operations.

Keep each update short enough to display comfortably. If a script replaces the file every few seconds while the expression takes much longer to move a message across the screen, viewers may miss information or see a changing message that no longer matches the surrounding programme. A useful operational rule is to change copy at deliberate editorial points, not simply whenever a source feed produces a new line.

If you use a scheduled updater, log the timestamp, source and result of each replacement. Do not log the YouTube stream key alongside those records. Test malformed input, an empty file, a missing file and characters outside the chosen font before leaving the process unattended.

Integrate the filter into the continuous stream

Once the overlay works locally, place the filter in the video portion of the FFmpeg command that sends the stream to YouTube. The broad shape is:

ffmpeg -re -i input.mp4 \
  -vf 'drawbox=... ,drawtext=...' \
  -c:v libx264 -b:v ... -maxrate ... -bufsize ... \
  -g ... -c:a aac -f flv 'rtmps://.../app/STREAM_KEY'

This is only a structural example. Replace the input, filter, codec, bitrate, keyframe settings, audio mapping and output URL with values suitable for the source and the current YouTube guidance. Do not paste a real stream key into a public script, screenshot, issue report or article. Treat it as a credential and rotate it through YouTube Studio if it is exposed.

YouTube’s current encoder guidance lists RTMP and RTMPS, H.264, H.265 and AV1 video, AAC or MP3 audio, constant bitrate and frame rates up to 60 fps. It recommends a two-second keyframe interval and says not to exceed four seconds. Use the official YouTube encoder settings for the codec, resolution and frame-rate combination you actually select.

Bitrate is not a universal constant. YouTube’s table varies its recommendations by codec, resolution and frame rate. For example, the current table lists 14 Mbps for H.264 at 1080p30. That figure applies to that configuration and should not be copied to a different output without checking the table. YouTube also recommends upload headroom on its streaming tips page, including 20 per cent headroom, but neither that guidance nor any encoder setting guarantees successful or uninterrupted ingestion.

The ticker filter consumes processing capacity because every video frame must be rendered and encoded again. A continuous stream should be tested on the actual host with the intended resolution, frame rate, font, input and audio. If the machine cannot maintain the target frame rate, reducing the output complexity or choosing a more capable host may be necessary. The overlay itself is not a substitute for sufficient CPU, upload capacity or process supervision.

For a broader unattended-stream design, the article on running a 24/7 stream with a Google Cloud VM discusses the host side. If your source is a playlist rather than one continuous input, scheduling different videos in a 24/7 channel is a separate concern from drawing the ticker.

The YouTube stream key connects the encoder feed to the selected live stream. Prepare the event in Live Control Room, start FFmpeg, inspect the preview and check stream health before relying on the channel overnight. YouTube recommends testing before starting and monitoring messages during the event. Keep a recovery plan for the FFmpeg process, but choose the supervisor and restart design for your own host rather than assuming the filter handles recovery.

For operators who do not want a computer running the FFmpeg process overnight, StreamNeo removes the need to keep the local machine on by taking an uploaded video, applying the YouTube connection details and running the continuous broadcast remotely with monitoring and automatic restart. That solves the unattended running problem, not the design of an FFmpeg ticker command, and it remains a YouTube-only workflow.

Test rendering separately from YouTube ingest

A local render is the fastest way to find visual problems. Use a short representative input and write a small output file, or preview the filter locally if your environment supports it. Include the real font, target dimensions, intended language and a message with punctuation similar to the live copy.

Check these points before connecting to YouTube:

  • The text is visible from its starting position rather than appearing already clipped.
  • The movement is smooth at the selected frame rate.
  • The whole message can be read at normal playback size.
  • The band does not cover important source content.
  • Accented characters, Devanagari or other required glyphs render correctly.
  • The ticker file reloads with a complete replacement rather than a partial sentence.
  • Audio remains present and aligned after video filtering.
  • FFmpeg maintains the intended frame rate without sustained processing delay.

Then test the ingest path with representative motion and audio. YouTube’s live streaming tips recommend testing before going live and leaving upload headroom. Start the stream in the Live Control Room, wait for the preview, and inspect the ticker as YouTube receives it. Look for dropped frames, warnings, delayed updates, audio faults and text that becomes unreadable after platform scaling.

A local file can prove that the filter renders. It cannot prove that YouTube will accept every future run, that the network will remain stable overnight or that a process will recover from every failure. Keep those as separate checks in your operating notes. The YouTube RTMP setup testing guide is useful when the filter is already working but the ingest path still needs validation.

For channels with a rotating visual source, avoid solving every problem in the ticker. Playlist looping, source continuity and text rendering are different layers. If the underlying loop ends unexpectedly, see the guidance on keeping a YouTube stream running when a playlist ends rather than adding more complexity to drawtext.

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

Does YouTube add the scrolling ticker?

No. YouTube receives the already encoded video, and the ticker must be rendered into its frames before upload. YouTube’s stream settings affect ingest and encoding expectations; they do not create or position the text.

Can I change the ticker file instantly?

No. reload controls how often FFmpeg rereads the file, and buffering can delay what viewers see. Replace the completed UTF-8 file atomically, then allow for the next reload and normal live playback delay.

Why does my ticker work locally but fail in the live command?

The full command adds shell quoting, re-encoding, audio mapping, output settings and an ingest connection. Test the filter separately, inspect the exact command received by FFmpeg, and then verify the codec, bitrate, keyframe interval, stream URL and key privately against YouTube’s current documentation.

Will a ticker make a continuous stream more reliable?

No. It changes the picture and adds some rendering and encoding work. Reliability still depends on the input, FFmpeg process, host, upload connection and YouTube ingest, so test and monitor those parts independently.

YOU’VE REACHED THE END

Keep the ideas coming.

More guides, useful tools and a little help for your next broadcast.

Back to the journal ↗
YOUR NEXT READ

A little more to explore.

More Streaming Settings guides ↗ · All topics ↗