A Jellyfin server plugin that adds a custom UI layer to Jellyfin Web and the Mobile App and cross-client settings synchronization. Includes an optional Jellyseerr integration with seamless authenticated proxy support.
- Custom Details Screen - Full-screen overlay with backdrop, logos, metadata, and a permission-aware context menu matching jellyfin-web's behavior
- Navigation Bar - Pill-shaped toolbar with Home, Search, Shuffle, Genres, Favorites, Library buttons, and user avatar
- Featured Media Bar - Hero slideshow with Ken Burns animation, content logos, and metadata overlay
- Jellyseerr Panel - Embedded Jellyseerr iframe with automatic session-based authentication via the server proxy
- Settings Panel - Per-user settings for all features, synced across clients
- TV Support - Spatial navigation and remote-friendly focus management for webOS/Tizen
- Settings Sync API - Per-user preference storage with merge/replace modes, synced across all Moonfin clients
- Jellyseerr Proxy - Authenticated reverse proxy that creates browser sessions automatically, so the iframe loads without a separate login
- Admin Configuration - Dashboard page for Jellyseerr URL, enable/disable toggles
- Web Injection - Serves the frontend JS/CSS as embedded resources, automatically injected via the File Transformation plugin
Disclaimer: Screenshots shown in this documentation feature media content, artwork, and actor likenesses for demonstration purposes only. None of the media, studios, actors, or other content depicted are affiliated with, sponsored by, or endorsing the Moonfin client or the Jellyfin project. All rights to the portrayed content belong to their respective copyright holders. These screenshots are used solely to demonstrate the functionality and interface of the application.
- Jellyfin Dashboard → Administration → Plugins → Repositories
- Add repository:
- Name:
Moonfin - URL:
https://raw.githubusercontent.com/Moonfin-Client/Plugin/refs/heads/master/manifest.json
- Name:
- Go to Catalog → find Moonfin → Install
- Restart Jellyfin
- Download the latest
Moonfin.Server-x.x.x.x.zipfrom Releases - Extract to your Jellyfin plugins folder:
Platform Path Linux /var/lib/jellyfin/plugins/Moonfin/Docker /config/plugins/Moonfin/Windows %ProgramData%\Jellyfin\Server\plugins\Moonfin\ - Restart Jellyfin
As of v1.1.0, Moonfin uses the File Transformation plugin to automatically inject its web UI. The JavaScript Injector plugin is no longer needed.
- Add the File Transformation plugin repository to Jellyfin:
- URL:
https://www.iamparadox.dev/jellyfin/plugins/manifest.json
- URL:
- Install the File Transformation plugin from the catalog
- Restart Jellyfin
- Force refresh your browser (Ctrl+Shift+R)
UI not loading? Go to Dashboard → Scheduled Tasks and run the Moonfin Startup task once, then refresh your browser.
Jellyfin Dashboard → Administration → Plugins → Moonfin to configure server-wide options like the Jellyseerr URL.
Once the web UI is loaded, click your user avatar in the top right to open the Settings panel and click Moonfin. From there you can customize the navbar, media bar, details screen, seasonal effects, ratings, and more. Settings are saved per-user and synced across all your Moonfin clients.
- .NET 8 SDK
- Node.js (LTS)
./build.sh.\build.ps1Both scripts accept optional parameters:
./build.sh [VERSION] [TARGET_ABI]
.\build.ps1 -Version "1.0.0.0" -TargetAbi "10.10.0"
The build will:
- Bundle the frontend JS and CSS
- Compile the .NET server plugin
- Package
Moonfin.Server.dllandmeta.jsoninto a ZIP - Update
manifest.jsonwith the new checksum
Output: Moonfin.Server-{VERSION}.zip in the repo root.
├── build.sh # Build script (Linux/macOS/Git Bash)
├── build.ps1 # Build script (Windows PowerShell)
├── backend/ # .NET 8 Jellyfin server plugin
│ ├── Api/ # REST controllers (settings, Jellyseerr proxy)
│ ├── Helpers/ # File Transformation patch callbacks
│ ├── Models/ # User settings, patch payload models
│ ├── Services/ # Startup task, settings persistence
│ ├── Pages/ # Admin config page HTML
│ └── Web/ # Embedded JS/CSS/HTML served to clients
└── frontend/ # Web UI plugin source
├── build.js # JS/CSS bundler
└── src/
├── plugin.js # Entry point
├── components/ # Details, Navbar, MediaBar, Jellyseerr, Settings
├── styles/ # Component CSS
└── utils/ # API helpers, storage, device detection, TV nav
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/Moonfin/Ping |
GET | Yes | Check plugin status and configuration |
/Moonfin/Settings |
GET | Yes | Get current user's settings |
/Moonfin/Settings |
POST | Yes | Save settings (merge or replace) |
/Moonfin/Settings |
HEAD | Yes | Check if user has saved settings |
/Moonfin/Settings |
DELETE | Yes | Delete user's settings |
/Moonfin/Jellyseerr/Config |
GET | Yes | Get Jellyseerr configuration |
/Moonfin/Jellyseerr/Proxy/* |
* | Session | Reverse proxy to Jellyseerr |
/Moonfin/Assets/{fileName} |
GET | Yes | Serve embedded rating icons |
Direction: Bidirectional, local-wins
Note: Not all settings listed below have been integrated into every client yet. The server model defines the full set of syncable settings. Each client only reads and writes the ones it currently supports. Unsupported fields are preserved on the server and ignored by clients that don't use them.
Settings stored on the server per-user and shared across all Moonfin clients.
| Setting | Type | Description |
|---|---|---|
navbarEnabled |
bool | Enable custom navbar |
navbarPosition |
string | Navbar position (top, side) |
showClock |
bool | Show clock in navbar |
use24HourClock |
bool | Use 24-hour time format |
showShuffleButton |
bool | Show shuffle button in toolbar |
showGenresButton |
bool | Show genres button in toolbar |
showFavoritesButton |
bool | Show favorites button in toolbar |
showCastButton |
bool | Show cast/remote playback button |
showSyncPlayButton |
bool | Show SyncPlay button |
showLibrariesInToolbar |
bool | Show library buttons in toolbar |
shuffleContentType |
string | Shuffle content type (movies, tv, both) |
mediaBarEnabled |
bool | Enable featured media bar |
mediaBarContentType |
string | Media bar content type (movies, tv, both) |
mediaBarItemCount |
int | Number of items in media bar |
mediaBarOpacity |
int | Media bar overlay opacity (0–100) |
mediaBarOverlayColor |
string | Media bar overlay color key |
seasonalSurprise |
string | Seasonal particle effect (none, winter, spring, summer, fall, halloween) |
mdblistEnabled |
bool | Enable MDBList ratings |
mdblistApiKey |
string | MDBList API key |
mdblistRatingSources |
list | Which rating sources to display |
mergeContinueWatchingNextUp |
bool | Merge Continue Watching and Next Up rows |
enableMultiServerLibraries |
bool | Enable multi-server library aggregation |
homeRowsImageTypeOverride |
bool | Override home rows image type |
homeRowsImageType |
string | Home rows image type (poster, thumb, banner) |
detailsScreenBlur |
string | Blur intensity for details background |
browsingBlur |
string | Blur intensity for browsing backgrounds |
themeMusicEnabled |
bool | Enable theme music playback |
themeMusicOnHomeRows |
bool | Play theme music on home rows |
themeMusicVolume |
int | Theme music volume (0–100) |
blockedRatings |
list | Content ratings to block |
jellyseerrEnabled |
bool | Enable Jellyseerr integration |
jellyseerrApiKey |
string | Jellyseerr API key |
jellyseerrRows |
object | Jellyseerr discovery row configuration |
tmdbApiKey |
string | TMDB API key for episode ratings |
These settings are stored in localStorage only and do not sync across clients:
| Setting | Description |
|---|---|
detailsPageEnabled |
Enable custom details screen |
mediaBarAutoAdvance |
Auto-advance media bar slides |
mediaBarIntervalMs |
Auto-advance interval in milliseconds |
backdropEnabled |
Enable backdrop images |
- Pings
GET /Moonfin/Pingto check if the server plugin is installed and sync is enabled - Fetches server settings via
GET /Moonfin/Settings - Three scenarios:
- Both local & server exist: Merges with local wins (
{ ...server, ...local }), then pushes the merged result back to the server - Server only (fresh install/new browser): Restores server settings to localStorage. This is how settings carry over to a new client
- Local only (no server data yet): Pushes local settings to the server
- Both local & server exist: Merges with local wins (
- Saves to localStorage immediately
- If server is available, also pushes to server via
POST /Moonfin/Settings
- When you open Jellyfin on a new device/browser with no local settings, it pulls from the server and your settings follow you
- If you change settings on Client A, they push to server. When Client B next loads (page refresh/login), it syncs but Client B's local settings win in the merge, so it won't overwrite unsaved local preferences
- Sync only runs once on initial page load, not continuously, so if two clients are open simultaneously, they won't live-sync between each other
- No conflict resolution beyond "local wins". If you change different settings on two clients without refreshing, the last one to refresh will overwrite the other's server-side changes
- No real-time push between clients (no WebSocket/polling)
- Sensitive data like
mdblistApiKeyis synced to the server (stored per-user)
We welcome contributions to Moonfin for Jellyfin Web!
- Check existing issues - See if your idea/bug is already reported
- Discuss major changes - Open an issue first for significant features
- Follow code style - Match the existing codebase conventions
- Test across clients - Verify changes work on desktop browsers and mobile
- Consider upstream - Features that benefit all users should go to Jellyfin first!
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes with clear commit messages
- Test thoroughly on desktop and mobile browsers
- Submit a pull request with a detailed description
- Issues - GitHub Issues for bugs and feature requests
- Discussions - GitHub Discussions for questions and ideas
- Upstream Jellyfin - jellyfin.org for server-related questions
Moonfin for Jellyfin Web is built upon the excellent work of:
- Jellyfin Project - The foundation and upstream codebase
- MakD - Original Jellyfin-Media-Bar concept that inspired our featured media bar
- Druidblack - Original MDBList Ratings plugin
- Moonfin Contributors - Everyone who has contributed to this project
This project is licensed under GPL-3.0. See the LICENSE file for details.
Moonfin for Jellyfin Web is an independent project and is not affiliated with the Jellyfin project.
← Back to main Moonfin project














