Scrob - Self-hosted media tracking app. It syncs your libraries from Jellyfin, Plex, and Emby.
100K+
Scrob syncs your libraries from Jellyfin, Plex, and Emby, tracks your watch history, ratings, and personal lists, and lets you push your activity back to Trakt — all from a clean, app-like web interface that installs as a PWA on any device.
Dashboard

Explore

Movie

Show

Season

Episode

Search

History (mobile)

Lists (mobile)

Settings

Images are hosted on Docker Hub (
bellamy/scrob). A mirror is also available on GHCR (ghcr.io/ellite/scrob) if you prefer.
curl -o docker-compose.yaml https://raw.githubusercontent.com/ellite/scrob/main/docker-compose.yaml
docker-compose.yaml and replace the required values:services:
scrob-db:
container_name: scrob-db
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: scrob
POSTGRES_PASSWORD: changeme # ← change this
POSTGRES_DB: scrob
volumes:
- db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U scrob -d scrob"]
interval: 5s
timeout: 5s
retries: 10
scrob:
container_name: scrob
image: bellamy/scrob:latest
restart: unless-stopped
depends_on:
scrob-db:
condition: service_healthy
ports:
- "7330:7330"
environment:
DATABASE_URL: postgresql+asyncpg://scrob:changeme@scrob-db:5432/scrob # ← match password above
SECRET_KEY: changeme # ← generate with: openssl rand -hex 32
TZ: UTC
volumes:
db_data:
docker compose up -d
# Create a dedicated network
docker network create scrob-net
# Start the database
docker run -d \
--name scrob-db \
--network scrob-net \
--restart unless-stopped \
-e POSTGRES_USER=scrob \
-e POSTGRES_PASSWORD=changeme \
-e POSTGRES_DB=scrob \
-v scrob_db:/var/lib/postgresql/data \
postgres:16-alpine
# Start Scrob
docker run -d \
--name scrob \
--network scrob-net \
--restart unless-stopped \
-p 7330:7330 \
-e DATABASE_URL="postgresql+asyncpg://scrob:changeme@scrob-db:5432/scrob" \
-e SECRET_KEY="$(openssl rand -hex 32)" \
-e TZ=UTC \
bellamy/scrob:latest
http://localhost:7330 and create your account.docker compose pull && docker compose up -d
Database migrations run automatically on startup — no manual steps required.
| Variable | Default | Description |
|---|---|---|
SECRET_KEY | — | Required. JWT signing key. Generate with openssl rand -hex 32. |
DATABASE_URL | — | Required. PostgreSQL connection string (postgresql+asyncpg://...). |
ENABLE_REGISTRATIONS | true | Allow new users to register. The first user can always register regardless of this setting. |
REGISTRATION_MAX_ALLOWED_USERS | 0 | Maximum number of registered users. 0 = unlimited. |
TZ | UTC | Container timezone (e.g. Europe/Lisbon). |
PUID | 1000 | User ID to run the process as. |
PGID | 1000 | Group ID to run the process as. |
BACKEND_PORT | 7331 | Internal port the backend binds to. Override only if 7331 conflicts on bare metal. |
OIDC_ENABLED | false | Enable OIDC login. |
OIDC_DISABLE_PASSWORD_LOGIN | false | Enforce OIDC-only login (disables username/password). |
See docker-compose.yaml for the full list of OIDC variables and other variables.
Scrob listens on port 7330. Place a reverse proxy (Caddy, Nginx, Traefik) in front for HTTPS — required for the PWA install prompt on non-localhost addresses.
# Caddyfile
scrob.yourdomain.com {
reverse_proxy localhost:7330
}
Remove the scrob-db service and set DATABASE_URL to your existing instance:
DATABASE_URL: postgresql+asyncpg://user:password@your-db-host:5432/scrob
Webhooks update your watch history and Continue Watching in real time. Each user's webhook URL is shown in Settings next to the relevant integration.
https://your-scrob-url/api/proxy/webhooks/{jellyfin|plex|emby}?api_key=YOUR_API_KEY
Playback Start, Playback Progress, Playback Stop, Mark Played.Movies and Episodes.Do not use a custom template — Jellyfin's template engine produces invalid JSON. "Send all properties" sends a well-formed payload that Scrob parses correctly.
Plex webhooks require a Plex Pass subscription.
Playback Start, Playback Progress, Playback Stop.Scrob supports any OpenID Connect provider (Authelia, Authentik, Keycloak, Google, etc.).
OIDC_ENABLED: "true"
OIDC_PROVIDER_NAME: "Authelia"
OIDC_CLIENT_ID: "scrob"
OIDC_CLIENT_SECRET: "your-secret"
OIDC_AUTH_URL: "https://auth.yourdomain.com/api/oidc/authorization"
OIDC_TOKEN_URL: "https://auth.yourdomain.com/api/oidc/token"
OIDC_USERINFO_URL: "https://auth.yourdomain.com/api/oidc/userinfo"
OIDC_REDIRECT_URL: "https://scrob.yourdomain.com/oidc-callback"
OIDC_AUTO_CREATE_USERS: "true"
# OIDC_DISABLE_PASSWORD_LOGIN: "true" # uncomment to enforce SSO-only
Register Scrob as a client in your provider with redirect URI: https://scrob.yourdomain.com/oidc-callback
Contributions are welcome — whether it's a bug report, a feature request, or a pull request.
/api/proxy/.Commit messages follow Conventional Commits — feat:, fix:, chore: — as releases and changelogs are generated automatically from them.
git clone https://github.com/ellite/scrob.git
cd scrob
# Start a local database
docker compose -f docker-compose-test-db.yaml up -d
# Copy and fill in the environment file
cp .env.exanple .env
# Edit .env — set POSTGRES_* and SECRET_KEY at minimum
cd backend
uv sync
uv run alembic upgrade head
uv run uvicorn main:app --reload --port 7331
cd frontend
npm install
npm run dev
The frontend dev server starts on http://localhost:4321 and proxies API calls to the backend on 7331.
Scrob is licensed under the GNU General Public License v3.0.
You are free to use, modify, and distribute Scrob, provided that any derivative works are also released under the GPLv3.
Content type
Image
Digest
sha256:406549e6e…
Size
229.6 MB
Last updated
8 days ago
docker pull bellamy/scrob