Why Your Jellyfin Server Deserves Better Analytics
Jellyfin gives you full control over your media library without subscriptions or data harvesting, but its built-in dashboard stops well short of telling you anything genuinely useful about how your server gets used. You can see who is currently streaming, but you cannot easily track which shows get abandoned halfway through, which users stream the most, or how your server load behaves over time. That gap is exactly what Jellystat fills.
Jellystat is an open-source statistics tracker built specifically for Jellyfin. It runs as a separate service, pulls data from the Jellyfin API on a schedule, and stores it locally in a PostgreSQL database. The result is a clean web dashboard showing playback history, user activity breakdowns, top content, and session logs – none of which requires sending your data anywhere outside your own network.
This guide walks through setting up both Jellyfin and Jellystat using Docker Compose, connecting them properly, and getting your dashboard populated with real data.

What You Need Before Starting
This setup assumes Docker and Docker Compose are already installed on your host machine. A Linux-based system is recommended – Ubuntu Server, Debian, or any distro you are comfortable managing remotely works fine. You will need at least 2GB of free RAM and enough storage for your media library plus database growth. Jellystat’s database stays lean for most home users, but active servers with many users will see it grow steadily over months.
You should also have a basic understanding of how Docker Compose files work – editing environment variables, mapping volumes, and exposing ports. If you have already run other self-hosted services like Seafile with OnlyOffice, the workflow here will feel familiar. The Jellystat container does require a Jellyfin API key generated from inside your Jellyfin admin panel, so your Jellyfin instance should be running and accessible before you configure Jellystat.
Port planning matters here. Jellyfin defaults to port 8096 for HTTP. Jellystat’s web UI runs on port 3000 by default. PostgreSQL runs internally on 5432 but does not need to be exposed to your host network unless you plan to query the database directly. Decide ahead of time whether you are running everything on a local network or exposing services through a reverse proxy.
Setting Up Jellyfin with Docker Compose
Create a working directory for your project. Inside it, create a docker-compose.yml file. The Jellyfin service needs three volume mounts: one for configuration data, one for cache, and one or more for your actual media. Map your media directories carefully – using read-only mounts for media keeps Jellyfin from accidentally modifying files. Set the PUID and PGID environment variables to match your host user so file permissions stay clean across restarts.
A minimal Jellyfin service block looks like this:
- image: jellyfin/jellyfin:latest
- container_name: jellyfin
- network_mode: bridge (or a custom Docker network if you prefer isolation)
- ports: “8096:8096”
- volumes: ./jellyfin/config:/config, ./jellyfin/cache:/cache, /your/media:/media:ro
- restart: unless-stopped
Run docker compose up -d jellyfin and navigate to http://your-server-ip:8096 to complete the initial setup wizard. Create your admin account, add your media libraries, and let Jellyfin finish its initial library scan before proceeding. Once you are in the admin dashboard, go to Dashboard – Advanced – API Keys and generate a new key. Label it something clear like “Jellystat” and copy it – you will paste it into the Jellystat configuration next.

Adding Jellystat to Your Compose Stack
Jellystat requires a PostgreSQL database, so your Compose file needs two additional services: one for Postgres and one for Jellystat itself. Both should share a Docker network with Jellyfin so Jellystat can reach the Jellyfin API by container name rather than IP address, which avoids breakage when containers restart and get new IPs.
Add the following to your docker-compose.yml:
- postgres service: image postgres:15, set POSTGRES_USER, POSTGRES_PASSWORD, and POSTGRES_DB environment variables, mount a volume for data persistence, and keep it on the shared internal network.
- jellystat service: image cyfershepard/jellystat:latest, set POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_IP (use the postgres container name), POSTGRES_PORT (5432), JWT_SECRET (any long random string), and JELLYFIN_SERVER (the full URL to your Jellyfin instance including port). Expose port 3000.
Once both containers are running, navigate to http://your-server-ip:3000. Jellystat will prompt you to create an admin account on first launch. After logging in, go to Settings and paste your Jellyfin API key. Set your sync interval – every 60 minutes works well for most setups, though you can drop it to 15 minutes if you want near-real-time data. Jellystat will immediately begin pulling historical session data from Jellyfin, so your dashboard will not start empty even if you just connected it to an existing Jellyfin server with months of watch history.
Reading the Dashboard and Staying on Top of Your Data
Jellystat’s main dashboard surfaces four core views: play history, top content, user statistics, and library overviews. The play history log is searchable and filterable by user, date range, and media type. Top content rankings show you which movies and episodes generate the most plays and total watch time – useful for deciding what to add more of, or what to safely prune from storage. User stats break down each account’s total watch time, session count, and most-played genres.
The library overview tells you how many items exist per library type and tracks when each was last synced. If you notice sync gaps – periods where no data appears despite the server being active – check that your Jellyfin API key has not expired or been regenerated in the Jellyfin admin panel. Jellystat logs sync errors in the Settings panel under Sync Logs, so diagnosing connection issues is straightforward rather than a guessing game.
For users who want to go deeper, Jellystat exposes its PostgreSQL database directly. Connecting a tool like TablePlus or DBeaver lets you run custom queries against raw session data – useful for generating reports that Jellystat’s UI does not natively support, like tracking which specific episodes cause users to drop a series or calculating average session length by time of day.

Once Jellystat has been running for a few weeks, the pattern that tends to surface fastest is how dramatically a single active user can skew total watch time numbers – and whether your server hardware is actually being used as hard as you assumed it was.





