
You want a countdown on air before a launch, a premiere or a New Year stream, without sitting at a keyboard. It has to reach zero at the announced time, switch to the live scene by itself and keep streaming while nobody watches the VPS. The countdown script that ships with OBS counts minutes from the moment its scene appears and never switches scenes, so this guide builds one that does both, tests it privately and leaves it running on Ubuntu 24.04 or Debian 12.
Quick answer: Load a small local HTML page into a Browser source. It counts down to a fixed time from the VPS clock and at zero calls window.obsstudio.setCurrentScene("Live"), which OBS only accepts when the source's Page permissions are at least Advanced access to OBS. Add looping music in a Media source, rehearse with a target three minutes ahead while recording, then start OBS with --scene "Countdown" --startstreaming and let Tools > Output Timer end the stream. OBS's bundled countdown.lua suits a plain "starting soon" timer, but it counts a duration and never switches.
What You Are Building
Two scenes, named exactly the same in OBS and in the page:
- Countdown: a background image or video, the countdown page in a Browser source, and music in a Media source.
- Live: what viewers get at zero, such as a premiere video, a "we are live" screen, or your camera sent to the VPS over RTMP or SRT as in our cloud OBS guide.
OBS has to run in a desktop session on the VPS already: the cloud OBS guide sets that up with VNC, our 24/7 OBS guide with a virtual display.
Which Timer Fits
| Countdown page in a Browser source | countdown.lua, bundled with OBS | |
|---|---|---|
| Counts to | A fixed date and time | A number of minutes from when its text source becomes active |
| At zero | Switches to your live scene | Shows its Final Text |
| After OBS restarts | Shows the right time again, because it reads the clock | Starts again from the full duration |
| In Safe Mode | Still runs, because the Browser source is a core module | Off, because Safe Mode disables scripting |
| Linux packages | OBS PPA and Flatpak, not Debian's own package | All of them |
Use the page for an announced time and for anything unattended. The script suits a few minutes of "starting soon" before a stream you start yourself; see its section below.
Step 1: Make Sure Your OBS Has a Browser Source
On Ubuntu 24.04, the official OBS PPA has OBS 32.2.0, and the obs-browser README lists the PPA among the builds with the Browser source. The cloud OBS guide shows the install.
Debian 12's own obs-studio package is OBS 29.0.2, with the bundled scripts but no browser plugin in its file list. Use the official Flatpak there, OBS 33.0.1 with the Browser source:
sudo apt install flatpak
sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
sudo reboot
Flathub's setup page asks for that restart. Reconnect, then:
sudo flatpak install flathub com.obsproject.Studio
flatpak run com.obsproject.Studio
With the Flatpak, use flatpak run com.obsproject.Studio wherever this guide starts obs; arguments after the app ID go to OBS. Space-Node's streaming VPS comes with OBS preinstalled and opens in your browser, so you can skip this step there.
Step 2: Write the Countdown Page
Create the file on the VPS:
mkdir -p ~/countdown
nano ~/countdown/countdown.html
Paste this page and edit the four lines at the top of the script:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
html, body { height: 100%; margin: 0; }
body {
display: flex; flex-direction: column;
align-items: center; justify-content: center;
color: #fff; font-family: sans-serif;
font-variant-numeric: tabular-nums;
}
#clock { font-size: 180px; font-weight: 700; }
#starts { font-size: 48px; }
</style>
</head>
<body>
<div id="clock">--:--:--</div>
<div id="starts"></div>
<script>
// Edit these four lines
const TARGET = "2026-11-20T19:00:00Z"; // event start; Z means UTC
const COUNTDOWN_SCENE = "Countdown";
const LIVE_SCENE = "Live";
const SHOW_ZONE = "Europe/Amsterdam"; // zone for the "Starts" line
const start = Date.parse(TARGET);
const clock = document.getElementById("clock");
const starts = document.getElementById("starts");
let switched = false;
if (Number.isNaN(start)) {
starts.textContent = "Check TARGET";
} else {
starts.textContent = "Starts " + new Date(start).toLocaleString("en-GB", {
timeZone: SHOW_ZONE, weekday: "short", hour: "2-digit",
minute: "2-digit", timeZoneName: "short"
});
}
function two(n) { return String(n).padStart(2, "0"); }
function tick() {
if (Number.isNaN(start)) return;
const left = Math.max(0, Math.ceil((start-Date.now()) / 1000));
const d = Math.floor(left / 86400);
const h = Math.floor(left / 3600) % 24;
const m = Math.floor(left / 60) % 60;
const s = left % 60;
clock.textContent = (d > 0 ? d + "d " : "") + two(h) + ":" + two(m) + ":" + two(s);
// At zero, switch once, and only if the countdown scene is on air
if (left === 0 && switched === false && window.obsstudio) {
switched = true;
window.obsstudio.getCurrentScene(function (scene) {
if (scene && scene.name === COUNTDOWN_SCENE) {
window.obsstudio.setCurrentScene(LIVE_SCENE);
}
});
}
}
tick();
setInterval(tick, 250);
</script>
</body>
</html>
TARGETis the start time asYYYY-MM-DDTHH:mm:ssZ, whereZmeans UTC; an offset such as2026-11-20T20:00:00+01:00works too. With neither, MDN says the time is read as local time, here the VPS's time zone.COUNTDOWN_SCENEandLIVE_SCENEare your scene names, spelled exactly as in OBS.SHOW_ZONEsets the time zone of the "Starts" line, any IANA name such asAmerica/New_YorkorUTC.
The page works out the time left from the clock on every tick, so it doesn't drift, and a reload shows the right time at once. At zero it switches once, and only if the countdown scene is on air, so a page running in the background can't pull you out of another scene. Both calls are part of obs-browser's JavaScript bindings. In your own browser the page counts down too, but window.obsstudio only exists inside OBS, so nothing switches.
Step 3: Add the Page to OBS
In the Countdown scene, click + under Sources, choose Browser and set:
- Local file: on, then pick
countdown.html. - Width and Height: your canvas size from Settings > Video > Base (Canvas) Resolution, such as 1920 and 1080. The default is 800 by 600.
- Page permissions: Advanced access to OBS (Change scenes, Start/Stop replay buffer, etc.). With the default, Read access to OBS status information, OBS drops the switch without a word in the log.
- Shutdown source when not visible: on. The page unloads while its scene is off air and loads fresh each time the scene is shown again.
The default Custom CSS makes the page background transparent, so keep the Browser source above your background image or video in the source list.
Step 4: Add Music and Check the Sound
Add a Media source to the Countdown scene, keep Local File on, choose your track and tick Loop (off by default). Restart playback when source becomes active is on by default, so the music starts from the top when the scene goes on air and stops at zero, because the Live scene doesn't contain it. Use music you are allowed to stream.
The VPS has no speakers and needs none: a Media source decodes the file inside OBS and hands the sound to the OBS mixer. Check three things:
- The music's meter moves in the Audio Mixer while the Countdown scene is on air.
- Under Edit > Advanced Audio Properties, its Audio Monitoring is Monitor Off. Monitor Only (mute output) keeps it out of the stream.
- In the Advanced output mode, the stream uses the Audio Track set under Settings > Output > Streaming, so the music needs that track ticked in the Tracks column.
If the page itself plays a sound, tick Control audio via OBS; otherwise the page plays to the system's own audio output, not into OBS.
The Simple Option: countdown.lua
For "starting soon" before a stream you start by hand, the bundled script works with every package, Debian's included:
- Add a Text (FreeType 2) source to the Countdown scene.
- Open Tools > Scripts and click +. The file dialog first opens in OBS's bundled scripts folder; pick
countdown.lua. - Set Duration (minutes), pick your text source under Text Source and type a Final Text. The default is "Starting soon (tm)".
The script starts counting when the text source becomes active, so when its scene goes on air, and starts over from the full duration each time the scene returns; Reset Timer, a button and a hotkey, restarts it. At zero it shows the Final Text and you switch yourself. Text sources created after you opened the script are missing from its list, but you can type the name.
Step 5: Rehearse Without an Audience
Print a target three minutes from now on the VPS:
date -u -d '+3 minutes' +%Y-%m-%dT%H:%M:%SZ
Paste the output as TARGET, save, and click Refresh cache of current page in the Browser source's properties. Put the Countdown scene on air and click Start Recording. At zero OBS should switch to Live and the music should stop. Stop the recording and play the file from the Recording Path in Settings > Output to check the sound.
Then test the platform end without viewers. On YouTube, give the test stream Private or Unlisted visibility, which YouTube's help says every streamer can choose. On Twitch, add ?bandwidthtest=true to the end of the stream key in Settings > Stream; Twitch's broadcast docs say it disables live viewing, and Twitch Inspector shows the stream's health. Remove it afterwards.
Finally, put the real TARGET back, refresh again and check the day and time on the "Starts" line.
Step 6: Leave It Running
Check the clock. The page counts against the VPS clock:
timedatectl
You want System clock synchronized: yes and NTP service: active. If not, sudo timedatectl set-ntp true enables and starts the first time sync service it finds; if none is installed, sudo apt install systemd-timesyncd adds one.
Start OBS on the countdown scene. OBS is a desktop program, so run this in the VPS's desktop session or your autostart entry:
obs --scene "Countdown" --startstreaming
End it on time. Under Tools > Output Timer, set "Stop streaming after" to the countdown plus the event, and tick Enable streaming timer every time; without it, the timer only starts with the stream while that window is open. When it fires, the log says Stopping stream due to OutputTimer timeout.
Leave reconnecting on. Automatically Reconnect under Settings > Advanced is on by default, with a Retry Delay of 2 seconds and 25 Maximum Retries. Our OBS auto reconnect guide covers the other reasons long streams drop.
Stop OBS cleanly. pkill -x obs sends SIGTERM, which OBS on Linux catches: it saves its settings and closes the same way File > Exit does. If a stream or recording is still running, OBS first shows an Active Outputs warning and waits for a click; Show active outputs warning on exit, under Settings > Advanced, turns that off. Avoid kill -9. SIGKILL can't be caught, so OBS 32 and 33 start next time with an OBS Studio Crash Detected dialog and wait for a click before anything runs, --startstreaming included. A crash or a hard reset of the VPS does the same. Choose Run in Normal Mode; Safe Mode disables third-party plugins, scripting and WebSockets.
Restart unattended. OBS marks each running session with a run_ file in ~/.config/obs-studio/.sentinel/ and deletes it on a clean exit; a leftover file is what triggers that dialog. A start script for a machine nobody watches can clear it first:
rm -f ~/.config/obs-studio/.sentinel/run_*
obs --scene "Countdown" --startstreaming
The Flatpak keeps that folder under ~/.var/app/com.obsproject.Studio/config/obs-studio/. Clearing it hides the crash from you, so read the log afterwards. If you want your own Ubuntu or Debian install for this, any Space-Node VPS gives you full root access on KVM.
If It Still Fails
Open the log with Help > Log Files > View Current Log, or search the newest one:
LOG="$(ls -t ~/.config/obs-studio/logs/*.txt | head -n 1)"
grep -E "tried to switch|OutputTimer|unclean shutdown|Safe Mode" "$LOG"
With the Flatpak, the logs are in ~/.var/app/com.obsproject.Studio/config/obs-studio/logs/.
- Zero passes, nothing switches and the log is quiet: Page permissions is below Advanced access to OBS, so OBS ignores the call. Also check that the scene on air is named exactly like
COUNTDOWN_SCENE. Browser source '...' tried to switch to scene 'Live' which doesn't exist:LIVE_SCENEdoesn't match the scene's name. Case and spaces count.- The page shows "Check TARGET": the time isn't in the
YYYY-MM-DDTHH:mm:ssZform. - The countdown is off by whole hours:
TARGEThas noZor offset, so it was read in the VPS's time zone, whichtimedatectlprints asTime zone. - The stream is silent: go through the three checks in step 4.
- Your edits don't show: click Refresh cache of current page.
- OBS didn't come back after a reboot: it's waiting at the crash dialog. See step 6.
FAQ
Can the page start the stream too?
Yes. With Page permissions at Full access to OBS, which OBS labels "Start/Stop streaming without warning", the page can call window.obsstudio.startStreaming(). Give that level only to a local file you wrote. Starting OBS with --startstreaming does the same job with less risk.
What happens if OBS or the VPS restarts during the countdown? The page reads the clock, so it shows the right time as soon as OBS loads it again. If OBS comes back on the Countdown scene after zero, the page switches to Live straight away. countdown.lua would start again from its full duration.
Does Studio Mode change anything? No. In Studio Mode the page's switch transitions the program output, not just the preview, and its on-air check reads the program scene.
How do I show the start time to viewers in other time zones?
Everyone sees the same picture, so print the time in the zone most of your viewers use. SHOW_ZONE takes any IANA name, and you can copy the "Starts" line in the page for a second zone.
How long can a countdown stream run? Set the end yourself with the Output Timer. If you want the replay on YouTube, its help says streams under 12 hours are archived automatically, so keep the countdown and the event together under 12 hours.
Sources
All opened on 31 October 2026:
- OBS Studio source at tag 33.0.1 (what this guide relies on also holds in 32.2.0, the Ubuntu 24.04 PPA version): countdown.lua, scripts.cpp, output-timer.cpp, obs-main.cpp, OBSApp.cpp, CrashHandler.cpp, OBSStudioAPI.cpp, OBSBasic.cpp, settings dialog, UI strings, Media source, core modules, releases
- obs-browser: README, UI strings, defaults, browser-client.cpp, obs-browser-source.cpp
- OBS Knowledge Base: Browser Source, Launch Parameters
- Packages: OBS PPA, Debian obs-studio, OBS on Flathub, Flathub manifest, Flathub setup for Debian, flatpak-run(1), flatpak-install(1), Flatpak conventions, systemd-timesyncd for Ubuntu 24.04 and Debian 12
- Platforms: YouTube: Create a live stream with an encoder, Twitch video broadcast docs, Twitch Inspector
- MDN: Date, Intl.DateTimeFormat, font-variant-numeric
- Linux: timedatectl(1), date(1), GNU date relative items, pgrep and pkill(1), signal(7)