Already running Plex and thinking about switching to Jellyfin? The good news: you don’t have to re-rip anything or “migrate” your media files at all — both point at the same folder on the same NAS. What actually needs migrating is your watch history: what’s been watched, what’s in progress, and your ratings. This guide covers that specifically, using a real, actively maintained tool built for exactly this.
Step 1 — Install Jellyfin first, pointed at the same media folder
If you haven’t already, follow the Jellyfin install guide and map it to the exact same /volume1/media path Plex is already using. Let Jellyfin finish its own library scan before moving on — the sync tool matches items by filename and metadata provider ID, so both servers need to actually know about the same files first.
Step 2 — Get a Plex token
Open Plex Web, play any item, click the ⋮ menu → Get Info → View XML. The URL that opens contains X-Plex-Token= followed by your token — copy everything after the equals sign. This is Plex’s own documented way to find it; no third-party tool required.
Step 3 — Get a Jellyfin API key
In Jellyfin, go to Dashboard → API Keys → +, give it a name like jellyplex-sync, and copy the generated key.
Step 4 — Set up JellyPlex-Watched
Make a docker/jellyplex-watched folder, and inside it a .env file:
PLEX_BASEURL=http://YOUR_NAS_IP:32400
PLEX_TOKEN=your-plex-token-from-step-2
JELLYFIN_BASEURL=http://YOUR_NAS_IP:8096
JELLYFIN_TOKEN=your-jellyfin-api-key-from-step-3
SYNC_INTERVAL=60
DRYRUN=True
Then in Container Manager → Project → Create, point it at that folder with this compose file:
services:
jellyplex-watched:
image: luigi311/jellyplex-watched:latest
container_name: jellyplex-watched
env_file: .env
restart: unless-stopped
DRYRUN=True makes the tool log what it *would* sync without actually changing anything in Jellyfin. Deploy it this way first and check the container logs — confirm it’s matching your actual titles correctly before you let it write anything.Step 5 — Go live
Once the dry run logs look right — real titles, sensible matches, no wall of “no match found” errors — edit the .env file to DRYRUN=False and redeploy the project. With SYNC_INTERVAL=60 it’ll re-sync every 60 minutes, which is enough to keep both servers agreeing on watch state during however long you run them side by side.
Step 6 — Decide how long to run both
There’s no rush to cut Plex off. Keep both servers running against the same media folder, with the sync tool bridging watch state between them, for as long as it takes everyone in the household to actually switch over. When you’re ready, stop the Plex container (the media files themselves are untouched either way) and remove the sync tool — its job is done once there’s nothing left to keep in sync.
That’s a full migration without touching a single media file or losing a watch history you’ve built up over years. The only thing that actually moved was the metadata.