Seven numbers, and what each one really counts
Each number below answers one question and misleads you on another. These are general meanings rather than a standard: every tool draws its own lines, so read its definition before you compare two reports.
| Number | What it generally counts | Where it misleads | What it helps you decide |
|---|---|---|---|
| Peak concurrent viewers | The most players open at the same moment | Says nothing about how long anyone stayed | Whether your viewer limit was big enough |
| Distinct viewers | Different people or devices across the whole show, matched on whatever the tool can see, such as a login or device | A phone then a TV can count as two; a family on one TV counts as one | How far the show reached |
| Sessions or plays | Each separate time a player started | A viewer who drops and comes back adds another | Read against distinct viewers: far more sessions than people suggests people kept getting knocked off |
| Watch time | Time spent actually playing, added up across everyone | A player left running in an empty room still adds up | Whether the show held people |
| Start-up time | The wait between pressing play and the first picture | An average can hide a slow minority | Whether people give up before they see anything |
| Buffering | How often the picture stopped to wait for data, and for how long | A count alone treats a blink and a long freeze as equal | Whether the encoder or delivery needs work |
| Location | A country or city worked out from the viewer's network | It is approximate, and a VPN shows the VPN's location | Where your audience is and whether your access rules fit |
If you want careful definitions to borrow, player documentation is a good place to look. Android's Media3 library separates time actively playing from time a viewer spent waiting, and gives rebuffer time as a share of playing plus waiting. Its guide also points out that a buffering state can be the first load, a real rebuffer or a wait after a seek, which is why those should not be lumped together. Apple's AVFoundation access log keeps comparable fields: stalls, duration played, and time until the item is ready to play.
Why two honest reports can disagree
Because nobody counts people directly. With HLS, which our channels play out alongside DASH, a player downloads a playlist and then short media segments, and on a live stream it keeps reloading the playlist to find new ones (RFC 8216 describes this). A server sees requests. Any viewer figure taken from them has to be worked out, and that step is where tools part ways: how long a gap ends a session, what makes two requests the same person, whether a muted background tab counts.
So our advice is to pick one tool and one definition, keep them, and compare your shows with each other. A trend measured the same way each week tells you more than a single figure held up against someone else's dashboard.
What your Primcast channel shows you
On live video hosting, the Live tab of each channel is where you read a show as it happens:
- Status gives the encoder's address, the rate it is sending, how long it has been on air, how much is going out and how many are watching.
- Viewers lists each viewer with country and player while the stream runs, and the list downloads as a spreadsheet.
- Transfer for the month can be watched in the dashboard as it grows, as the video CDN page explains.
- Paid shows add a second, firmer count: the paywall in our player gives you a daily sales chart, how many members joined or left, and spreadsheets of every sale and viewer.
Our CDN page describes that list as who is watching this minute, so treat a download as a snapshot. Take one near your peak and another as you wrap, unless you have checked that a single file covers the whole show.
Two different places get called a location. The country in the viewer list describes the viewer. The nearest of our 5 cities is where the video is served from, and a viewer in one country can easily be served from a city in another.
A quick read while you are on air
A short routine during the show gives you time to act. Hand it to whoever is not running the cameras.
- Compare the rate the encoder is sending with the bitrate you set. If it sags, start with your own line and encoder, and expect every viewer to share the problem.
- Watch the viewer count against your channel's limit. Our CDN page calls that figure a hard limit, so a crowd close to it needs a decision before the next show, not during it.
- Scan the country and player columns when complaints come in. Complaints that cluster in one player or one country point somewhere much narrower than "the stream".
- Note the clock time of anything odd, such as a sudden drop in viewers. You will want to line it up with your rundown afterwards.
Measuring watch time and buffering in your own player
Buffering happens on the viewer's screen, so the player is the place to measure it. Our player page notes that a stream's HLS and DASH addresses are standard ones, so Video.js, Shaka or an app's own player can play them if you build your own. Once you do, a few standard browser events give you start-up time, stalls and time played.
The sketch below is ours, not a Primcast feature. It suits a player you built yourself: it needs a video element on your own HTTPS page, plus an address on your site that stores what it receives. Run it before playback starts: if it misses the first play, start-up and stalls stay empty. The report arrives as plain text holding JSON, so have /stats parse the body itself. Try it on a rehearsal first.
// Your own page, your own video element. /stats is your own address.
const v = document.querySelector('video');
const report = { id: crypto.randomUUID(), startMs: null, stalls: 0, stallMs: 0 };
let askedAt = null, stalledAt = null;
v.addEventListener('play', () => { askedAt ??= performance.now(); });
v.addEventListener('playing', () => {
const now = performance.now();
if (report.startMs === null && askedAt !== null) report.startMs = Math.round(now - askedAt);
if (stalledAt !== null) { report.stallMs += Math.round(now - stalledAt); stalledAt = null; }
});
v.addEventListener('waiting', () => {
if (report.startMs !== null && !v.seeking && stalledAt === null) {
report.stalls += 1;
stalledAt = performance.now();
}
});
function playedSeconds() {
let s = 0;
for (let i = 0; i < v.played.length; i++) s += v.played.end(i) - v.played.start(i);
return Math.round(s);
}
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
const openMs = stalledAt === null ? 0 : Math.round(performance.now() - stalledAt);
navigator.sendBeacon('/stats', JSON.stringify({ ...report, stallMs: report.stallMs + openMs, playedS: playedSeconds() }));
}
});
- Keep the latest report per id. The block sends each time the tab is hidden, and every report carries running totals, so adding them up would double count. Anything played after the last hide is not reported.
- The id marks a session, not a person. It is made fresh on each page load and never stored. Counting distinct viewers needs something steadier, such as a sign-in.
- Start-up is timed from the
playevent, so it means something when a viewer presses play or your code callsplay(). With the autoplay attribute, that event can arrive once the video is already ready, and the figure reads close to zero. - The first load and seeks are left out of the stall count, for the reason Media3 gives above. A pause during a stall adds the whole pause to that stall's length.
- Time played comes from the
playedranges, so a stretch watched twice after rewinding counts once. On a straight live viewing the two match. - Stall share is your headline figure: add up
stallMsacross sessions, then divide it by total played time plus totalstallMs.playedSis in seconds, so multiply it by 1,000 first. It is a close cousin of Media3's rebuffer ratio. - In a phone app, use the platform's own tools instead:
PlaybackStatsListenerin Media3, or the access log in AVFoundation.
What to change when a number looks wrong
Find your symptom, then change one thing and compare at the next show. The causes here are our reading of what usually lies behind each pattern, so treat them as the first thing to check, not a verdict.
| What you see | Check first | What to change |
|---|---|---|
| Encoder rate sags and everyone complains | Your upload, measured on the broadcasting machine | Keep video plus audio to about two thirds of your upload, or drop to 720p. On a shaky line use SRT, available from Starter up |
| Encoder rate holds, viewers buffer anyway | The keyframe interval | Set a fixed 2 seconds and turn off scene-change keyframes, as our live streaming tutorials explain |
| Stalls mostly on weak or mobile connections | Whether one bitrate is being sent to everyone | Lower the bitrate, or use adaptive bitrate transcoding on Platinum so the player can step down before the picture freezes |
| Complaints from one region | Reach from there: the data centers page lists a test IP and speed test for each city | Ask a viewer there to run it and send you the result before you change the encoder |
| Complaints from one player | Play the HLS link yourself on that device, on mobile data if you can | If it fails there alone, the fix belongs to that player or device |
| Countries you did not expect | Whether your link has been shared around | Use the country, IP and website rules, or expiring signed links, both on every plan |
| Peak close to your viewer limit | Whether it was a one-off night | Move up a plan for regular crowds, or use the event builder for a single big date |
| Viewers leave at the same moment | Your rundown at that clock time | If nothing stalled, the cause is the show rather than the stream: a long break, a dull segment, a late start |
Writing it up for a sponsor or your board
A good report says what was counted as plainly as how many. Our event page suggests keeping the viewer spreadsheet for exactly this.
- Name the definition next to the figure. "Peak of viewers at the same time, read from the Live tab" survives a follow-up question; "views" does not.
- Report restream platforms on their own lines. People watching on YouTube, Facebook or Twitch are watching on those platforms, so use each platform's own figures and do not total them with your player's: someone can be on two at once.
- Say when a snapshot was taken, so nobody reads a peak-time list as the whole audience.
- Trim before you forward. Open the spreadsheet and remove what the reader does not need, and share totals by country rather than rows where you can. Under EU rules, an online identifier can be personal data. That is general information, not legal advice.
Questions people ask
- How do I find out how many people watched my stream?
- Decide which figure you mean first: the biggest crowd at one moment, or the reach across the whole show. On a Primcast channel the Live tab shows how many are watching and lists each viewer with country and player. If you sell tickets, the paywall's sales spreadsheet is your firmest headcount, though a family sharing one ticket still counts once.
- How much buffering is too much?
- We know of no official threshold that fits every audience, so we will not quote one. Measure the share of time spent stalled, keep the definition fixed, and compare each show with the last. A rise after you changed the encoder settings or the venue tells you more than any industry figure could.
- Why don't my numbers match the ones on the social platforms?
- They are counting different audiences with different rules. A restream goes out to YouTube, Facebook or Twitch, and each platform counts its own viewers by its own definition. As we read it, your channel's list covers people on your own player, not those watching on the platforms. Read them side by side and do not expect them to agree.
- Can I see which city my viewers are in?
- The viewer list gives each viewer's country. Anything finer is a best guess worked out from a network address, so treat city figures from any tool as approximate. Do not read the CDN's serving city as the viewer's home: it is simply the nearest of the 5 cities the video is delivered from.