Set up and maintain

Statistics

What the dashboard's analytics panel actually shows

RamTV has a built-in analytics engine in the Stats section of the admin sidebar, organised into five pages: Dashboard, Visits, System, Users and Financial. This article explains what every number and graph on those pages measures, where the data comes from, how often it updates, and where the built-in system falls short of a dedicated web-analytics tool.

How the data is collected

The engine works in three stages, and understanding them explains almost every behaviour on the Statistics pages:

  • Collect — raw events are written continuously as people use the site: every server-rendered page request, every payment attempt, every playback attempt/start/end, every API call outcome and every media conversion job is logged to its own raw table the moment it happens.
  • Aggregate — a recurring background job (“Statistics Rollup”, see below) reads those raw tables and writes daily totals — one row per metric, per day, optionally broken down by a dimension such as gateway, country or endpoint — into a single summary table. This is a full delete-and-rewrite of that day's numbers each time, not an incremental add, so a metric that looked wrong never drifts further wrong — the next rollup replaces it cleanly.
  • Read — every chart and KPI on the Statistics pages reads only the daily summary table, never the raw logs directly. This is why the pages stay fast even on a site with millions of raw events, and why a metric always shows as zero rather than an error on a product that hasn't started collecting it yet (a fresh install, or a plugin that was only just enabled).
Today's number is always partial
The rollup treats “today” as still in progress and rewrites it on every run. If you check a KPI at 9am, today's total only reflects activity up to whenever the rollup last ran — it is not stale data, it simply hasn't finished happening yet.

The Statistics Rollup cronjob

The aggregation step runs as one of RamTV's scheduled cron jobs (see the Installation docs for what a cronjob is and how to confirm yours is actually running). It is named Statistics Rollup in Setting → Cronjob → Run logs, is always on, and re-processes yesterday and today every 15 minutes. There is nothing to configure. Re-processing yesterday as well as today on every run means a rollup that failed or ran against incomplete data self-corrects on its very next run — there is no separate “backfill” step to remember.

If a metric on any tab reads zero across the board even though the underlying feature is clearly being used, check two things in order: that the Statistics Rollup job shows recent successful runs under Setting → Cronjob → Run logs, and that the cronjob itself is actually being triggered on your server at all (see the Installation article for how to test that from the command line).

Data retention

Setting → General → Statistics has three retention controls:

SettingDefaultWhat it controls
Keep daily statistics for (days)400How far back the daily summary table is kept. Every chart reads only this table, so a period comparison further back than this reads as zero — 400 days is deliberately a bit over a year so year-over-year comparisons still work.
Keep raw event logs for (days)14How long the raw, per-event logs (playback events, API outcomes) are kept before cleanup. These exist only to be rolled up and to debug a rollup that looks wrong, so they don't need to be kept nearly as long as the daily summaries.
Dismissed alert cooldown (days)7How long a dismissed “Needs attention” alert (Dashboard tab) stays hidden before it can reappear if the underlying problem is still happening.

Dashboard tab

The landing tab, meant to answer “is anything wrong, and what changed” in one screen.

  • Needs attention — an automated checklist, not a raw metric: gateways stuck under a 20% approval rate (with at least 3 attempts in the period), a playback failure rate above 20% (with at least 5 attempts), cron jobs that failed or never finished in the last day, new recurring error signatures, and subscriptions expiring within 7 days. An empty list means the checks ran and found nothing, not that nothing was checked.
  • Right now — live activity, not from the daily rollup.
  • Active users / Plays / New users — this period vs. the period before it.
  • Listening hours / Playback success rate / Revenue (USD) — same comparison. Revenue here is USD only — other currencies are never blended into it; see the Financial tab for a true per-currency breakdown.
  • What changed — payment gateways / top request endpoints — the biggest movers versus the previous period, not simply the biggest totals.
Which playback the Dashboard's Plays/Listening-hours/Playback-success cards show
These three specific cards are wired to music playback metrics in shared framework code and will read zero on RamTV — that is a display gap, not a data gap: movie and episode playback is being tracked correctly in the same underlying system, it simply isn't surfaced on these three cards yet.

Visits tab

  • Real visitors — distinct IP addresses making a real request in the period.
  • Requests — total real requests in the period.
  • Top countries / What people request most — ranked breakdowns with the change vs. the previous period.
  • Platform mix — desktop vs. mobile, by request count.
“Real” specifically excludes one thing
Every Visits number explicitly excludes a background keep-alive polling request the client makes — on a typical install that single poll makes up roughly 70% of all raw requests, and counting it would make every visit number meaningless. It is the only traffic filtered out: there is no bot-detection, crawler filtering or IP-based de-duplication beyond “distinct IP this period”. A shared office network, CGNAT ISP or a search-engine crawler can all still inflate these numbers.

System tab

Operational health, aimed at diagnosing the server rather than the audience.

  • Job health — every cron job that ran in the period, with run count, failures, jobs that never finished (“hung”) and average duration.
  • API health — requests, errors and average latency per endpoint, sorted by error rate.
  • Media processing — what happened to every uploaded file: “skip” means the file was already in a compatible format and needed no work; “copy”/“copy_video” means the stream was remuxed rather than re-encoded (fast); “encode” means it had to be converted, with the reason column naming exactly which compatibility check failed. This panel needs FFprobe enabled (see the FFmpeg article) — without it, every file reads as no_probe and is always fully re-encoded.
  • External dependencies — success rate and latency per external host your server talks to (payment gateways, metadata providers, etc.) — answers “is it us or is it them” for a slow or failing integration.
  • Top error signatures — PHP errors grouped by file and line, so recurring problems surface once instead of drowning in individual occurrences.
  • Firewall activity — hits and blocks per rule (see the Firewall article for how the underlying protection works).
  • Files — counts, storage size and a breakdown by file type and by which feature the file belongs to.

Users tab

  • DAU / WAU / MAU — distinct signed-in users active on the range's last day / trailing 7 days / trailing 30 days. “Active” means the account performed at least one tracked action — guest/anonymous visits are never counted here, only signed-in activity.
  • Stickiness — average DAU as a percentage of MAU. A falling stickiness with a flat MAU is usually the earliest sign of an engagement problem, before total user counts move at all.
  • Activation funnel — of the users who registered in the period, how many verified their account and how many ever completed a play/stream.
  • Engagement distribution — among active users in the period, how many had 0, 1-5, 6-20 or 20+ plays — shows whether “active” means a broad casual audience or a small group of heavy users.
  • Retention cohorts — a 6-week grid: of the users who signed up in a given week, what percentage were still active in each week since. Reads down a column to see whether retention is improving for more recent signup cohorts.

Financial tab

  • Payment attempts / Approved payments / Approval rate — all keyed by the day the payment was created, not the day it was approved — so the numbers read as a true cohort: of what was attempted this day, how much of it eventually succeeded.
  • Gateway scorecard — attempts, paid, approved, approval rate and revenue for every gateway that saw at least one attempt in the period. A gateway stuck at 0% approval is losing revenue outright, not merely underperforming — worth checking against the Dashboard tab's automated alert for the same condition.
  • Payment funnel — where attempts are actually lost: at the gateway itself, or at the approval step after reaching it.
  • Revenue by currency — deliberately never summed into one blended figure across currencies, since that total would be arithmetically meaningless. Compare currencies side by side instead.

Movie playback is tracked from a fresh install (Movie is part of the base product). TV episode playback is only tracked if the separately-sold TV plugin is installed — without it, there is simply no TV/episode data for the system to collect.

Should you also run Google Analytics?

The built-in Statistics pages and Google Analytics answer different questions, and running both is reasonable rather than redundant:

  • The built-in engine knows things Google Analytics structurally cannot: your own payment gateway approval rates, cron job health, FFmpeg/media conversion outcomes, API error rates, and exactly which track/movie/episode was played, skipped or finished — all of it tied directly to your own database records (a track ID, a subscription plan, a gateway name), not to an external, sampled, cookie-dependent platform.
  • Google Analytics is stronger at the things the built-in engine deliberately doesn't attempt: marketing-channel attribution (which campaign, referrer or search term brought a visitor in), cross-device and cross-session identity stitching, audience demographics, and comparison against industry benchmarks.
  • The built-in “Real visitors”/“Requests” numbers on the Visits tab are a coarse operational signal (server load, which endpoints are hot), not a marketing-analytics replacement — they have no bot filtering beyond the one keep-alive exclusion described above, no session/attribution modelling, and no geographic detail beyond country.

In practice: keep the built-in Statistics pages as your operational and revenue source of truth (they're the only place that can tell you a gateway is failing or a cron job is hung), and add Google Analytics if you specifically need marketing-channel attribution or audience demographics that the built-in system was never designed to measure.