Written for somebody who has never seen this system: a feature list you can hand to a QA person, with the exact steps to prove each feature works and what a failure looks like. Every check below is something you can do from a browser and a terminal in a few minutes.
You need: this server's address, an operator password, OBS (or ffmpeg), and VLC. Nothing else.
| Check | You should see | If not |
|---|---|---|
Open /healthz | ok | The server is not running or the address is wrong. Stop here. |
| Open Admin → Health | A list of green rows, some blue INFO | Any BAD row is a real problem — read its "→" line, which says what to do |
| Find the Database row on Health | MariaDB with a host | "In-memory only" means every channel, account and invoice is lost on the next restart. Do not run a business on this. See the admin guide, "Are you running a real database?" |
What it is for. Anyone can create an account and be streaming in about a minute, without an operator doing anything.
| Check | Expected |
|---|---|
| Sign up with an email that already exists | Refused, with a message saying so |
| Sign up with a 4-character password | Refused |
| Sign in with the wrong password | Refused, and the message does not say whether the email exists |
| Log out, then press the browser's Back button | You are not signed in. A logout ends the session on the server, not only in the browser |
What it is for. A channel is one stream: an ingest key to publish to, and a set of URLs to watch it on.
test1) → Create.# or without OBS
ffmpeg -re -f lavfi -i testsrc2=size=1280x720:rate=30 \
-c:v libx264 -b:v 2500k -preset veryfast -g 60 \
-f flv rtmp://YOUR-HOST:1935/live/YOUR-STREAM-KEY
| Check | Expected |
|---|---|
| Open the channel's player link | Picture within a few seconds |
Open the .m3u8 in VLC | Same picture. This proves it is a real HLS stream, not a browser trick |
| Publish with a wrong stream key | Refused at the door. The channel stays off air and nothing appears |
| Stop OBS, wait, start it again | The channel returns to ON AIR by itself |
| Try to create a second channel | Refused — every plan includes one channel. This is deliberate |
What it is for. Keeping what went out so viewers can watch it later. Two different settings, and confusing them is the most common mistake:
| Check | Expected |
|---|---|
| Play the recording | It plays start to finish |
| Reload the channel page | Keep recordings for still says 7. If it reverted to 0 the form is discarding your input — report it |
| Stop the encoder mid-broadcast, restart it within two minutes | One recording covering both halves, not two. It plays through the join without stopping |
| Stop the encoder and leave it off for five minutes | A new recording starts. Yesterday's broadcast must not be appended to today's |
What it is for. Letting a viewer scrub backwards through a live stream — they arrive late and watch from the start of the programme.
RAM or disk. RAM is fast and limited by a memory budget; disk allows
much longer windows. On this server disk spools can live on their own volume
(-dvr-dir), because DVR is the one thing that writes continuously.
| Check | Expected |
|---|---|
| Scrub back four minutes | It plays from there |
| Scrub back further than the window | It clamps to the oldest point it still has, rather than stalling |
| Leave it publishing for an hour with a 5-minute window | Disk use stops growing. A window that grows forever is a bug |
| Set the window to 0 | Live only, no scrub bar |
What it is for. Making a stream unusable to anyone you have not allowed.
.m3u8
links that worked before will start returning 403. Use the embed code from the
channel's player code page, which handles tokens for you.
| Check | Expected |
|---|---|
Tick Secure, then open the raw .m3u8 with no token | 403 |
| Open the channel's embed link | Plays — it fetches a token itself |
| Take a working token and change one character | 403 |
| Wait for the token to expire, keep watching | Playback continues — the player fetches a new one before the old expires |
| Set a viewer cap of 1 and open two players | The second is refused |
What it is for. Putting the stream on somebody else's website. The channel's player code page gives ready-made snippets:
| Snippet | Use it for |
|---|---|
| Web (hls.js) | Any website. Handles tokens and reports playback quality |
| iOS / Android / Roku | Native apps |
| VLC / ffmpeg | Proving a channel works without a browser |
| Recording / catch-up | Embedding one past broadcast |
| Live with rewind (nDVR) | Live with a seekable timeline |
| Check | Expected |
|---|---|
| Paste the web snippet into a blank HTML file and open it | Plays |
| Do the same on a channel with Secure on | Still plays — the snippet fetches a token. If it 403s, the snippet is missing token handling; report it |
| Use the catch-up snippet with a real recording id | Plays that recording |
| Play through the web snippet, then look at the channel's analytics | A start time appears. Viewers on embedded players must be counted |
Per channel (customer's own dashboard): viewers now, peak, bytes, watch time, where viewers are, and playback quality — startup time, stalls, errors, broken down per rendition.
Across all customers (Admin → All customers): the whole box added up, then split per account — channels, live channels, viewers, egress, watch hours. This is the operator's view; a customer never sees it.
| Check | Expected |
|---|---|
| Watch a channel from two browsers | Viewers reaches 2 within a few seconds |
| Close both | It returns to 0 within a minute or so |
| Admin → All customers | The customer publishing shows live channels and viewers; idle customers show zero |
| Restart the server, reopen analytics | Yesterday's per-minute history is still there. Live counters restart from zero, which is correct |
What it is for. Standing up a lineup — a set of channels that all get the same treatment — without configuring each by hand. Admin → Capacity → Provision a lineup.
Enter comma-separated names, pick a profile (OTT switches on recording, catch-up, low latency, a public listing and a DVR window), pick protection (AES-128, DRM or none), a DVR length, and optionally an owner account. Each channel comes back with its own ingest key and embed code.
| Check | Expected |
|---|---|
| Provision three channels with the OTT profile and AES | Three channels, each with its own key, all with Secure on and the DVR window set |
| Run the same request again | Existing names are reported as already taken rather than being duplicated or overwritten |
| Leave Owner blank | The channels belong to the operator |
| Put a customer's user id in Owner | They appear on that customer's dashboard, even though their plan includes one channel — an operator may provision beyond a plan |
| Check | Expected |
|---|---|
| As a customer: Support → open a ticket | It appears in your tickets as open |
| As operator: Admin → Support inbox | The ticket is there |
| Reply as operator | The customer sees the reply on their own support page |
| Sign in as a different customer | They cannot see the first customer's ticket |
dev, and no money moves. Health says so. Any revenue figure you see
before then is test data.
| Check | Expected |
|---|---|
| Upgrade a test account to Business | Its plan changes and paid features unlock |
| Try a Business-only feature (DVR) on a Pro account | Refused, naming the plan needed |
| Downgrade that account back to Free | The paid feature is switched off, not left running |
| Admin → Billing console | The account, its plan, its channel count and its invoices |
These cannot be tested on a laptop, and a tester should not record them as failures:
| Feature | Needs |
|---|---|
| Server-side ABR, live bar | A GPU node (gpunode or GPUFF) reachable from this server |
| Widevine / FairPlay DRM | A licence server |
| Push to YouTube / Facebook | A real stream key on that platform |
| Per-customer S3 storage | A real bucket and credentials |
| Geo blocking | Viewers with real public addresses — everything is "local" from one office |
| HTTP/3 advertisement | UDP/443 reachable from outside; prove it with ssh101 -h3check from another machine first |
An engineer needs four things, and rarely gets them: the section number above, the channel slug, what you saw instead, and the time (so the audit log and the server log can be lined up). A screenshot of the whole browser window — including the address bar — is worth more than a description.