https://github.com/ellite/scrob
Scrob - Self-hosted media tracking app. It syncs your libraries from Jellyfin, Plex, and Emby, tracks your watch history, ratings, and personal lists — Your own private Letterboxd + Trakt
https://github.com/ellite/scrob
Last synced: 2 months ago
JSON representation
Scrob - Self-hosted media tracking app. It syncs your libraries from Jellyfin, Plex, and Emby, tracks your watch history, ratings, and personal lists — Your own private Letterboxd + Trakt
- Host: GitHub
- URL: https://github.com/ellite/scrob
- Owner: ellite
- License: gpl-3.0
- Created: 2026-04-15T21:47:59.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-04-16T00:04:12.000Z (2 months ago)
- Last Synced: 2026-04-16T00:26:25.129Z (2 months ago)
- Language: Astro
- Size: 27 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
- awesome-debrid - Scrob - self-hosted Trakt+Seer+Pulsarr alternative. (*Arr Stack & Automation / Hosting Providers (VPS, Seedbox..))
README
Scrob
Open-source, self-hosted media tracking — your personal Letterboxd + Trakt.
[](https://github.com/ellite/scrob/stargazers)
[](https://hub.docker.com/r/bellamy/scrob)
[](https://github.com/ellite/scrob/graphs/contributors)
[](https://github.com/sponsors/ellite)
[](https://github.com/ellite/scrob/releases/latest)
---
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.
## Table of Contents
- [Features](#features)
- [Screenshots](#screenshots)
- [Getting Started](#getting-started)
- [Docker Compose](#docker-compose)
- [Docker Run](#docker-run)
- [First Setup](#first-setup)
- [Updating](#updating)
- [Configuration](#configuration)
- [Development](#development)
- [Webhooks](#webhooks-real-time-scrobbling)
- [OIDC / Single Sign-On](#oidc--single-sign-on)
- [Contributing](#contributing)
- [Contributors](#contributors)
- [License](#license)
## Features
- **Multi-source sync**: Import your full library, watch history, and ratings from Jellyfin, Plex, and Emby. Incremental syncs keep everything up to date.
- **Real-time scrobbling**: Webhooks from Jellyfin, Plex, and Emby update your watch state as you play — no manual sync needed.
- **Trakt integration**: Sync your watched history and ratings from Trakt, and push Scrob activity back to Trakt automatically.
- **Watch history & ratings**: Track every movie and episode you've watched. Rate them on a 10-point scale with optional reviews.
- **Season ratings**: Rate individual seasons separately from the overall show.
- **Personal lists**: Create and curate lists of movies and shows. Mark them public to share with other users on the same instance.
- **Comments**: Leave comments on movies, shows, seasons, and episodes.
- **Social**: Follow other users and see their activity.
- **TMDB integration**: Rich metadata for every title — posters, backdrops, cast, crew, trailers, collections, and more.
- **Search**: Search TMDB across movies, shows, people, and collections, merged with your local library data.
- **Trending & Airing Today**: Daily trending movies and shows from TMDB, plus episodes airing today filtered to your collection.
- **Continue Watching & Next Up**: Dashboard cards showing in-progress items and the next episode to watch in each series.
- **Season & episode tracking**: Detailed season views with per-episode watched state and progress.
- **Cast & crew pages**: Full filmography for any person, linked to your library.
- **Radarr & Sonarr integration**: Add movies and shows to Radarr/Sonarr directly from the Scrob UI.
- **Two-Factor Authentication**: TOTP-based 2FA with backup codes, managed from the settings page.
- **OIDC / SSO**: Authenticate with any OpenID Connect provider (Authelia, Authentik, Keycloak, etc.).
- **Progressive Web App**: Install Scrob on any device — Android, iOS, or desktop — for a native app feel.
- **Single container**: Frontend and backend ship as one image on one port. No separate services to manage.
## Screenshots
View screenshots
**Dashboard**

**Explore**

**Movie**

**Show**

**Season**

**Episode**

**Search**

**History (mobile)**

**Lists (mobile)**

**Settings**

## Getting Started
### Prerequisites
- [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/)
- A [TMDB API key](https://www.themoviedb.org/settings/api) (free) — used for metadata, search, and images
### Docker Compose
> Images are hosted on **Docker Hub** (`bellamy/scrob`). A mirror is also available on GHCR (`ghcr.io/ellite/scrob`) if you prefer.
1. Download the compose file:
```bash
curl -o docker-compose.yaml https://raw.githubusercontent.com/ellite/scrob/main/docker-compose.yaml
```
2. Edit `docker-compose.yaml` and replace the required values:
```yaml
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:
- scrob_data:/app/backend/data
volumes:
db_data:
scrob_data:
```
3. Start:
```bash
docker compose up -d
```
### Docker Run
```bash
# 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
```
### First Setup
1. Open `http://localhost:7330` and create your account.
2. Go to **Settings → Integrations** to add your TMDB API key and connect Jellyfin, Plex, or Emby.
3. Select which libraries to sync, then trigger your first sync from **Settings → Sync**.
### Updating
```bash
docker compose pull && docker compose up -d
```
Database migrations run automatically on startup — no manual steps required.
## Configuration
| 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.
### Reverse proxy
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
}
```
### External PostgreSQL
Remove the `scrob-db` service and set `DATABASE_URL` to your existing instance:
```yaml
DATABASE_URL: postgresql+asyncpg://user:password@your-db-host:5432/scrob
```
## Webhooks (Real-time Scrobbling)
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
```
### Jellyfin
1. In Jellyfin, go to **Dashboard → Plugins → Catalogue**, install **Webhook**, then restart.
2. Go to **Dashboard → Plugins → Webhook → Add Generic Destination**.
3. Paste your Scrob Jellyfin webhook URL.
4. Enable notification types: `Playback Start`, `Playback Progress`, `Playback Stop`, `Mark Played`.
5. Enable item types: `Movies` and `Episodes`.
6. **Leave the Template field blank** and check **"Send all properties (ignore templates)"**.
> 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
Plex webhooks require a **Plex Pass** subscription.
1. Go to [plex.tv/account](https://www.plex.tv/account/) → **Webhooks → Add Webhook**.
2. Paste your Scrob Plex webhook URL.
3. In Scrob → Settings, enter your **Plex username** so events are attributed to the right account.
### Emby
1. In Emby, go to **Dashboard → Notifications → Add Notification → Webhook**.
2. Paste your Scrob Emby webhook URL.
3. Enable events: `Playback Start`, `Playback Progress`, `Playback Stop`.
## OIDC / Single Sign-On
Scrob supports any OpenID Connect provider (Authelia, Authentik, Keycloak, Google, etc.).
```yaml
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`
## Contributing
Contributions are welcome — whether it's a bug report, a feature request, or a pull request.
- **Issues**: Open an issue for bugs, questions, or feature ideas.
- **Pull Requests**: Fork the repo, create a branch, and submit a PR. Please follow the existing code style (Astro components for UI, FastAPI for backend) and make sure all browser-initiated API calls go through `/api/proxy/`.
Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/) — `feat:`, `fix:`, `chore:` — as releases and changelogs are generated automatically from them.
## Contributors
## Development
View instructions
### Requirements
- Python 3.12+, [uv](https://docs.astral.sh/uv/)
- Node.js 22+
- PostgreSQL 16 (via Docker is easiest)
### Setup
```bash
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
```
### Backend
```bash
cd backend
uv sync
uv run alembic upgrade head
uv run uvicorn main:app --reload --port 7331
```
### Frontend
```bash
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`.
## License
Scrob is licensed under the [GNU General Public License v3.0](LICENSE).
You are free to use, modify, and distribute Scrob, provided that any derivative works are also released under the GPLv3.
## Links
- The author: [henrique.pt](https://henrique.pt)
- Scrob Landingpage: [scrob.app](https://scrob.app)
- Join the conversation: [Discord Server](https://discord.gg/anex9GUrPW)