[![Build][build-shield]][build-url]
[![Release][release-shield]][release-url]
[![Coverage][codecov-shield]][codecov-url]
[![Docker Pulls][docker-shield]][docker-url]
[![Image Size][size-shield]][size-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url]
[![AI-Assisted][ai-shield]][ai-url]
[![Buy me a coffee][kofi-shield]][kofi-url]

What lands on Plex: a real "Picked for You" row from the maintainer's server, visible only to
its owner. Four "watched" ticks have been painted out.
## What it does
Everyone on a Plex server has the same blank-screen problem: a huge library and no idea what to put
on. Plex's own recommendation rows are identical for every account and ignore what _you've_ watched.
**Shortlist gives every user their own rows.** For each person it reads their own Plex watch history,
picks titles from your library they haven't seen but probably want to, explains each one, and puts
them on that person's Plex Home as rows: **"Picked for You"**, "Because you watched", "Watch it
again", seasonal picks and more. Rows rebuild on a schedule you choose, and each personal row is
visible only to its owner.
**Rows are hidden before they are shown.** Each row is labelled, every other account's Plex share
filter is told to hide that label, and only then is the row promoted to Home. A row is never visible
to the wrong person, not even briefly.
**It slots into the stack you already run.** Watch history comes straight from Plex. Candidates come
from TMDB and Trakt. Gaps can be handed to **Radarr/Sonarr** or **Overseerr/Jellyseerr**. Kometa's
collections are left completely alone.
**An assistant can help configure it.** Optional [MCP access](docs/guides/assistant-access.md) lets
local or hosted assistants view Shortlist or manage its supported settings, rows and normal saved
runs. The owner chooses **View only** or **Manage Shortlist** for each named connection. Normal runs
use the configured services and may incur provider charges; sensitive changes still need browser
approval.
**Requirements and limits:**
- Plex only. The privacy model relies on Plex's label-based share filters, so there is nothing to
port to Jellyfin or Emby.
- Needs Plex Media Server 1.43.2.10687 or newer and **Plex Pass** on the admin account.
- The server owner can see every row, in the library's Collections tab. Plex keeps them off the
owner's own Home.
- Container only. There is no Windows, macOS or Linux installer.
## Why this couldn't exist before 2026
Plex has no per-user collections. Its "hide by label" share setting is the only way to keep a row
from some people, and until 2026 it wasn't applied everywhere, so a row meant for one person still
turned up for others. Plex fixed that: label hiding now works on the Home and Recommended shelves
(PMS 1.43.1) and on Related rows (PMS 1.43.2). Shortlist is built on that fix. The **order** of the
steps (label, hide from everyone else, then promote) is what stops a row ever being visible before it
is private.
## What it looks like
| Start each row from a template | Add as many rows as you like |
| --------------------------------------------------------------------- | -------------------------------------- |
|  |  |
| Every pick, and _why_ it was picked | Watch every run, step by step |
| ------------------------------------------------------ | ------------------------------------------------ |
|  |  |
App screenshots come from a test library, not a real server. The titles are real films and shows,
but nobody pictured here watched anything.
## Features
**Personalized discovery**
- ๐ค **Private rows for every user**, built from _their_ watch history and visible only to them. The
owner gets rows too, so it's worth running on a one-person server.
- ๐ง **Picks that exist, with no AI key needed.** Every pick is a title verified to be in your library,
never invented. Ranking and the reasons are written in code. An optional AI provider (Claude, GPT,
Gemini, or a local server such as Ollama, llama.cpp, LM Studio, vLLM or LocalAI) powers one extra
source: a live web search for current, well-reviewed titles that TMDB and Trakt miss.
- ๐ **Web search that works with _any_ model, even offline ones.** Shortlist runs the search itself,
so your model never needs internet access. Use your provider's own web search, an
[Exa](https://exa.ai) key, or your own [SearXNG](https://docs.searxng.org).
[How it works](https://shortlistapp.dev/guides/ai/#the-source-that-uses-ai)
- โ๏ธ **AI instructions.** Tell AI web search what to look for, server-wide or per row.
[Details](https://shortlistapp.dev/guides/rows/what-goes-in/#ai-instructions)
- ๐ฌ **Every pick explains itself**: "Because you watched X", with the reason written in code.
- โจ **Describe a row in plain words.** An AI row turns "slow-burn heist films" into a themed row: the AI
writes the theme once, you check it and try it on one person first, and every night after that fills
each person's row from it with no AI. [How it works](https://shortlistapp.dev/guides/ai/#an-ai-row)
- ๐ญ **Explore: a new theme every few days.** Switch an AI row to Explore and each person gets their own
fresh theme on a schedule, written a day early so you can change it. Over-time controls swap more or
less each night, stop titles coming back for a while, and keep a row out of titles in your other rows.
- ๐ **Whole shows, not episodes.** A 20-episode binge counts as one show, so one series can't drown
out everything else.
**Make it yours**
- ๐๏ธ **Six row kinds, eleven templates.** Picked for You, Because you watched, Watch it again, Popular on
this server (shared), Seasonal and Your requests. Start each row from a template (Fresh finds, From
the vault, Movie night, More TV to watch and the AI's Describe a row are the others) rather than a blank form. Every row has
its own sources, size, libraries, cadence and audience, and you can add as many as you like.
- ๐๏ธ **A rebuild cadence you control**: nightly, weekly, monthly or never, so nobody opens Plex to a
completely reshuffled row every day.
- ๐ **Seasonal rows**: one row that follows the calendar: Halloween, Christmas, Valentine's Day plus twenty
ready-made holidays, film days and spotlights such as Thanksgiving and Easter, or your own dates. Picked for each person and
hidden between seasons.
- ๐ซ **Block a bad seed.** A film someone put on for a friend shouldn't shape their picks. Block it
from a run's "How we picked" page. The watch stays in their Plex history and just stops seeding.
- ๐ **Row placement**: choose which Plex shelf each row lands on (Home, the library's Recommended
tab, or both) and where it sits.
- ๐จ **Custom row posters (optional)**: upload artwork or generate it from text, reusing your AI key.
**Grow your library**
- ๐ฅ **Fills its own gaps (optional).** When a great pick isn't in your library, Shortlist can ask
**Radarr/Sonarr** for it, or file a request in **Overseerr/Jellyseerr**. Off by default and
cautious: the strongest few auto-send each night, and the rest wait in a **Requests** inbox for
one-click approval. Genres and TMDB tags you pick (concert films, say) never auto-send.
- ๐ฌ **A "Your requests" row.** What each person asked for in Overseerr (or tagged with their name in
Radarr/Sonarr), once it's on Plex and until they've watched it. Private per person, newest first,
no AI. A person with nothing ready simply has no row.
**Trust and safety**
- ๐ **Private by design.** Rows are delivered hidden and only revealed once the exclusions that hide
them exist. Share filters are snapshotted before the first change, and one uninstall flow restores
your server exactly as Shortlist found it.
- ๐ **Know if it's working.** A dashboard tracks what was delivered against what people actually
watched, per user and per row, and separates a title they **started** from one they **finished**.
- ๐ฅ๏ธ **A clear dashboard.** Dashboard, Users, Privacy, Runs (with a per-person "How we picked") and Activity pages, including
"Changes on Plex", a row editor with a jump list, and four-tab Settings. See [the interface guide](https://shortlistapp.dev/guides/interface/).
- ๐งช **Safe mode.** Set `SHORTLIST_DRY_RUN=1` to try it against your real server without writing a
single change.
- ๐ฆ **Homelab-native**: one container, a `/config` volume, a multi-arch image on GHCR, a healthcheck
and an Unraid template.
## Where it fits
Shortlist does one narrow thing the rest of the stack doesn't: build a **different** collection for
each person and keep it private, inside Plex. It is designed to sit alongside what you already run:
- **It never touches what it didn't make.** Only collections carrying Shortlist's own `shortlist_*`
label are ever modified โ Kometa's collections, and anything you built by hand, are skipped.
- **It can be told to stand aside.** Every row also carries a plain `shortlist` label, so a tool that
reorders the same shelf can exclude all of them with one entry โ Agregarr's _Exclude from Ordering
(Plex Label)_, for instance. Or turn Shortlist's own shelf ordering off entirely.
- **It merges share filters, never rebuilds them.** Existing conditions are left byte-for-byte
identical, and the originals are snapshotted before the first change.
- **It connects rather than duplicates.** Tautulli for nicer display names, Radarr/Sonarr or
Overseerr for gaps, Trakt and MDBList for candidates. All optional. Only Plex and a free TMDB key
are required.
Curious how the privacy works? See [How to make a Plex collection visible to only one user](https://shortlistapp.dev/plex-per-user-collections/).
## Quick start
**You'll need:**
- Somewhere to run a **Docker container**. It can be a different machine from Plex, as long as it
can reach it.
- Plex Media Server **1.43.2.10687 or newer**, with **Plex Pass** on the admin account.
- A free **TMDB API key**.
Optional: Tautulli, an AI provider key. Details in
[Getting started](https://shortlistapp.dev/getting-started/).
Save this as `docker-compose.yml`:
```yaml
services:
shortlist:
image: ghcr.io/stevezau/shortlist:latest
ports: ["5959:5959"]
volumes: ["./config:/config"]
environment:
- TZ=Etc/UTC
- PUID=1000
- PGID=1000
restart: unless-stopped
```
Run `docker compose up -d`, then open **http://your-host:5959** and follow the setup wizard. It
connects your Plex account, picks your server, and walks you to your first rows in about ten
minutes. A single `docker run` command and the Docker Hub image are in
[Other ways to install](https://shortlistapp.dev/getting-started/#other-ways-to-install).
To try it without touching your server first, add `SHORTLIST_DRY_RUN=1` under `environment:`.
Shortlist will show what it _would_ do and write nothing to Plex.
`:latest` is the latest stable release; `:dev` (`ghcr.io/stevezau/shortlist:dev`) is the development
build. Back up `/config` before switching, and don't downgrade a migrated database in place.
## Documentation
**[shortlistapp.dev](https://shortlistapp.dev/)** is the docs as a website.
| Page | What's in it |
| ------------------------------------------ | --------------------------------------------------- |
| [Getting started](https://shortlistapp.dev/getting-started/) | Install, wizard, first run |
| [Guides](https://shortlistapp.dev/guides/) | Rows, schedules, requests, AI cost, troubleshooting |
| [Reference](https://shortlistapp.dev/reference/) | Settings, API, env vars |
| [FAQ](https://shortlistapp.dev/faq/) | Privacy model, Kometa, uninstall |
### How Plex itself works
Background on Plex, not on Shortlist. Worth reading before you build anything similar yourself,
because most advice on the subject predates Plex's 2026 fixes and quietly leaks.
| Page | What's in it |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [Per-user collections](https://shortlistapp.dev/plex-per-user-collections/) | The label + share-filter mechanism, and the order that leaks |
| [Improving Plex's recommendations](https://shortlistapp.dev/improve-plex-recommendations/) | What Manage Recommendations really changes, and where it stops |
| [Recommendations from watch history](https://shortlistapp.dev/plex-recommendations-watch-history/) | What Plex does with history, and why smart collections aren't personal |
| [AI recommendations](https://shortlistapp.dev/plex-ai-recommendations/) | Where a model helps, and where it invents films you don't own |
| [Tools compared](https://shortlistapp.dev/plex-recommendation-tools/) | Shortlist, Immaculaterr, Curatarr, Diskovarr, Kometa and others |
## Support the project
Shortlist is free, MIT-licensed and built in evenings. Helping is optional. It runs nightly on the
maintainer's own 40-user server.
- **[Star it on GitHub](https://github.com/stevezau/shortlist)** โ free, and it is how other Plex
owners find Shortlist.
- **[Buy me a coffee on Ko-fi](https://ko-fi.com/stevezau)** โ no account needed. It buys time, not
features on request.
## Get help
- **Something broken?** Open the **Have an issue?** page in Shortlist. It runs read-only checks that
often name the cause outright, then opens a pre-filled issue with a secrets-free diagnostic.
- **Not sure it's a bug?** Ask in
**[Discussions โ Q&A](https://github.com/stevezau/shortlist/discussions/categories/q-a)**. Answers
get marked as answers, so the next person with the same problem finds one.
## License
MIT ยฉ Steven Adams
[build-shield]: https://img.shields.io/github/actions/workflow/status/stevezau/shortlist/ci.yml?branch=master&style=for-the-badge&label=build&labelColor=a06a00
[build-url]: https://github.com/stevezau/shortlist/actions/workflows/ci.yml
[release-shield]: https://img.shields.io/github/v/release/stevezau/shortlist?style=for-the-badge&label=release&color=a06a00
[release-url]: https://github.com/stevezau/shortlist/releases
[codecov-shield]: https://img.shields.io/codecov/c/github/stevezau/shortlist?style=for-the-badge&labelColor=a06a00
[codecov-url]: https://codecov.io/gh/stevezau/shortlist
[docker-shield]: https://img.shields.io/docker/pulls/stevezzau/shortlist?style=for-the-badge&color=a06a00
[docker-url]: https://hub.docker.com/r/stevezzau/shortlist
[size-shield]: https://img.shields.io/docker/image-size/stevezzau/shortlist/latest?style=for-the-badge&label=image&color=a06a00
[size-url]: https://hub.docker.com/r/stevezzau/shortlist/tags
[stars-shield]: https://img.shields.io/github/stars/stevezau/shortlist.svg?style=for-the-badge&color=a06a00
[stars-url]: https://github.com/stevezau/shortlist/stargazers
[issues-shield]: https://img.shields.io/github/issues/stevezau/shortlist.svg?style=for-the-badge&labelColor=a06a00
[issues-url]: https://github.com/stevezau/shortlist/issues
[license-shield]: https://img.shields.io/github/license/stevezau/shortlist.svg?style=for-the-badge&color=a06a00
[license-url]: https://github.com/stevezau/shortlist/blob/master/LICENSE
[ai-shield]: https://img.shields.io/badge/AI--Assisted-Claude%20Code-8A2BE2?style=for-the-badge&logo=anthropic&logoColor=white
[ai-url]: https://claude.com/claude-code
[kofi-shield]: https://img.shields.io/badge/Buy%20me%20a%20coffee-FF5E5B?style=for-the-badge&logo=kofi&logoColor=white
[kofi-url]: https://ko-fi.com/stevezau