Troubleshooting & FAQ
Quick Diagnostic Checklist
- Session server running? (
curl http://localhost:3000/health) - Plugin installed? (Check Dashboard > Plugins)
- Script tag in Custom HTML? (Dashboard > General) — or is file-transformation installed?
- Browser cache cleared? (Ctrl+F5)
- Correct WebSocket URL configured?
- Firewall allowing the session server port (default 3000)?
- Using the Discord bot? See Discord Bot below.
Related: Core Structure for expected system behavior, Security for authentication/CORS issues, Configuration for server and plugin settings.
Common Issues
Watch Party Button Not Visible
- Check Custom HTML configuration — Dashboard > General > Branding should have:
<script src="../JellyWatchParty/ClientScript"></script> - Hard refresh the browser (Ctrl+F5 / Cmd+Shift+R), or clear the cache completely
- Check browser console (F12) — a
404means the script wasn’t found (plugin not installed); aCORSerror means the WebSocket was blocked (check CORS config) - Verify plugin is installed — Dashboard > Plugins should show “JellyWatchParty”; check Jellyfin logs for plugin load errors
- On Jellyfin 12, update to the latest JellyWatchParty release — versions before the Jellyfin 12 UI fix only checked whether
.headerRightexisted, not whether it was visible; Jellyfin 12’s default “modern” layout keeps it in the DOM but hidden, so the button silently failed to appear with none of the symptoms above present. Fixed versions detect this and fall back to a floating button anchored next to the user-menu avatar. - On Jellyfin 12, the floating button overlaps another plugin’s button — that fallback anchors next to the user-menu avatar the same way some other plugins do (e.g. JellyPrivateLibraries); JellyWatchParty automatically detects and steps around any other plugin’s own floating button there. If it’s still overlapping, both plugins may be older than the versions with this fix — update both.
- The floating button should be replacing SyncPlay but isn’t — this only happens when the admin has enabled “Hide native SyncPlay button” in JellyWatchParty’s plugin config; with that off, the button floats next to the toolbar instead of over SyncPlay’s icon (this is expected — see Configuration).
Cannot Connect to Session Server
- Check server is running:
docker ps | grep sessionandcurl http://localhost:3000/health - Check firewall:
nc -zv localhost 3000, open the port if needed (sudo ufw allow 3000/tcp) - Check the WebSocket URL — browser console shows the attempted URL; should be
ws://host:3000/wsorwss://host:3000/ws - Check CORS — session server logs show CORS errors; set
ALLOWED_ORIGINSto include your Jellyfin URL
Sync Issues
Participants out of sync, playback drifting apart, or frequent jumping/stuttering:
- Wait a few seconds — initial sync takes 2-3 seconds and drift correction is gradual by design
- Host: pause and play again to re-sync everyone
- Check network quality — high latency causes sync issues; check RTT in the panel (ideal < 100ms)
- HLS/transcoding — transcoded streams have higher latency; try direct play or reduce quality if network is slow
- Check everyone has the same media — different versions may have different durations
Technical details: Sync Algorithms.
Room Closes Unexpectedly
Causes: the host disconnected (network dropped, browser closed, computer slept) and didn’t reconnect within 90 seconds and no other participant remained to be promoted; or the server restarted (rooms are in-memory/ephemeral). Check server logs for errors if this happens with a stable host connection.
Technical details: Core Structure: Host Disconnect.
Authentication Errors
- Check JWT configuration matches — plugin JWT Secret must match server
JWT_SECRET; both must be configured or both must be empty - Check token expiration — default 1 hour; refresh the page for a new token
- Rate limiting — max 10 token requests per minute; wait and try again
- JWT Secret is set but very short — the widget shows “Offline” and changing the Session Server URL setting seems to have no effect: check the Jellyfin server logs for repeated errors on
GET /JellyWatchParty/Token. A JWT Secret under 32 characters is treated as unusable and disables authentication (see Configuration: JWT Secret Guidelines) — set a proper secret withopenssl rand -base64 32, or clear the field entirely to explicitly run without authentication.
HLS Streaming Issues
Sync works initially but drifts during playback, frequent buffering interrupts sync, position jumps backward, or “false pauses” trigger unwanted sync events. HLS chunks video into small segments, causing buffering gaps, position reporting delays, and readyState changes during segment loads. JellyWatchParty filters most of this automatically (see Sync Algorithms: HLS Handling); if issues persist:
- Reduce bitrate/quality in Jellyfin playback settings
- Prefer Direct Play or Direct Stream over full transcoding (Dashboard > Playback > Active Devices shows which is in use)
- Safari uses native HLS (not hls.js) and may report
readyStatedifferently during buffering — keep the tab in focus, or use Chrome/Firefox
Rate Limiting Issues
| Limit | Value | Applies To |
|---|---|---|
| Token requests | 10/min | Per user, plugin endpoint |
| WebSocket messages | 30/sec | Per client connection |
| Message size | 64 KB | Per message |
Usually caused by rapid page refreshes/reconnection attempts (token limit) or spamming play/pause/seek (message limit) — normal usage won’t hit either. Check server logs: docker logs session-server 2>&1 | grep -i "rate".
Panel Opens But Empty
Wait for the WebSocket to finish connecting (“Connecting…” status), check the browser console (F12) for JavaScript/script-loading errors, and clear the browser cache in case an old script version is cached.
Discord Bot
Setup is in the Discord Bot guide. Work through these in order:
/jwpdoesn’t appear in Discord. In the admin panel, check that Bot enabled is on and Server ID is the server’s number (right-click the server > Copy Server ID, with Developer Mode on). Check that the bot was invited with theapplications.commandsscope. After you save the Server ID, allow up to 30 seconds. If it still doesn’t appear, checkdocker logs jwp-discord-bot.- “Watch parties from chat are turned off on this server”. Bot enabled is off in the admin panel.
- The chip reads “No bot token” or “Bot offline”. Run
docker psand check thatjwp-discord-botis up. It only starts with--profile discord. Both containers need the same token: the session server’sDISCORD_INTEGRATION_TOKENand the bot’sJWP_INTEGRATION_TOKEN. The token must be at least 32 characters (openssl rand -hex 32). If Discord rejectsDISCORD_BOT_TOKEN, the bot log saysDiscord connection ended for good (bad token or intents?). - The session server logs
Chat integrations: NOT started - .... The reason follows the dash. Common causes:DATA_DIRis unset (the compose files set/data);DISCORD_INTEGRATION_TOKENis missing or too short;INTEGRATION_HOSTis a name rather than an IP address (localhostis not accepted);INTEGRATION_PORTequalsPORTorADMIN_PORT. The bot also needs the admin panel running (ADMIN_PASSWORDset,ADMIN_ENABLEDnotfalse) and the Jellyfin devices settings (JELLYFIN_URL,JELLYFIN_API_KEY). - The bot’s
JWP_INTEGRATION_URLcan’t reach the session server. The bot’s default ishttp://session-server:3002. The quick-start compose usesjwp-session, which sets the URL explicitly. If you changedINTEGRATION_PORT, the URL must change too. - A user gets “wrong name or code” with the right code. The bot gives the same answer for a wrong name, a wrong code and a locked code, on purpose. Check the Jellyfin user name, then the admin panel: a code marked Locked: too many wrong tries needs New code. If the Discord account was blocked for too many wrong codes, wait for the 15-minute window to end. Bot activity lists the attempts with the Discord account id.
- A correct code is refused with “already linked”. The Jellyfin user is linked to a different Discord account. An admin unlinks the old account under Users and link codes, or assigns a new code.
/jwp device addsays “Devices can’t be added as host/receiver on this server”. That role is turned off in Devices may be added as host / receiver. The device list only shows devices that are open in a Jellyfin app signed in as you.- “The room already has a host; only its owner can change that”. Anyone can add a device as host only while a room has no host. After that, only the owner or an admin can change it. Add the device as receiver instead.
- A Discord room disappeared. Rooms close when the session server restarts, and when nobody is in them for Close empty rooms after minutes (default 30). Links and settings survive a restart.
- Codes stop working after you move or restore the data. The
secret.keyfile inDATA_DIRis missing or was replaced. A new key is created silently, and every existing code stops matching. Restore the wholejwp-datavolume, or assign new codes.
Log Analysis
Session server: docker logs session-server (or -f to follow). Look for Client connected/disconnected, Room created/closed, SECURITY: Wildcard origin (CORS warning), Message too large, Invalid token.
Jellyfin: Docker (docker logs jellyfin), Linux (/var/log/jellyfin/), Windows (%ProgramData%\Jellyfin\Server\log\). Look for [JellyWatchParty] JWT authentication is enabled. or [JellyWatchParty] JwtSecret is not configured.
Browser console: F12 > Console, filter by “JWP”. [JWP] Loaded, [JWP] Connected, [JWP] Disconnected, [JWP] Room joined.
Network Debugging
// In browser console — check WebSocket state
console.log(JWP.state.ws?.readyState);
// 0 = CONNECTING, 1 = OPEN, 2 = CLOSING, 3 = CLOSED
curl http://localhost:3000/health
npm install -g wscat && wscat -c ws://localhost:3000/ws
Or open Developer Tools (F12) > Network tab > filter “WS” to inspect WebSocket messages directly.
Performance Issues
High CPU (server): check number of rooms/clients. High CPU (client): reduce video quality, close other tabs, check for JS errors.
Memory (server): rooms are in-memory (~1KB/client, ~5KB/room); restart to clear if needed.
Slow sync: reduce SYNC_LEAD_MS if latency is low, increase if latency is high (see Sync Algorithms); check client hardware.
Reset Procedures
Client: clear browser cache/cookies, hard refresh, or in console: localStorage.clear(); location.reload();
Server: docker restart session-server (clears all rooms)
Plugin: Dashboard > Plugins > JellyWatchParty > clear all fields > Save > restart Jellyfin
Frequently Asked Questions
General
What is JellyWatchParty? A Jellyfin plugin that lets multiple users watch the same video in sync — when the host plays, pauses, or seeks, everyone follows automatically.
Is it free? Yes, open source and free to use.
Does it work with Plex or Emby? No — it uses Jellyfin’s plugin API and web interface specifically.
Do all participants need Jellyfin accounts? Yes, everyone needs access to the same Jellyfin server and media library.
Setup
Why do I need a separate session server? Jellyfin’s plugin architecture doesn’t support WebSocket endpoints, so a separate lightweight server handles real-time communication between clients.
Can I run everything on one machine? Yes — Jellyfin and the session server use different ports (8096 and 3000 by default).
Is Docker required? No, but recommended. See Installation for native build options.
Why do I need to add a script tag manually? Since Jellyfin 10.9, plugins can’t automatically inject scripts for security reasons — the manual step (or the file-transformation plugin) ensures administrators explicitly approve script injection.
Usage
Who controls playback? The host (room creator) — their play/pause/seek actions are mirrored to all participants. Democratic mode (all participants controlling playback) is planned.
What happens if the host leaves? A brief disconnect (network blip, backgrounded app) is invisible to participants for 90 seconds while the server waits for reconnection. If the host doesn’t return and other participants remain, the earliest-joined one is automatically promoted to host and the room stays open. It only closes if no one is left.
Can I use the official Android TV app (or Fladder) in a watch party? Yes. An admin adds the device to a room from the session server’s admin panel, as host (it drives the room) or receiver (it follows the room’s play/pause/seek and is started on the room’s item automatically; Fladder can only host). On trusted servers an admin can also let users bridge their own devices from the Watch Party panel via the Native Client Bridge (receivers there must already be playing the same item, and the room must not be password-protected).
Can I chat with other viewers? Yes — real-time text chat in the panel, with the last 50 messages replayed to late joiners/reconnecting clients.
Can I make a room private? Yes, with an optional password set at room creation.
Does everyone need the same video quality? No — each client transcodes independently; sync is based on playback position, not video quality.
Sync Quality
How accurate is the sync? Typically within 100-200ms, using clock synchronization and drift correction.
Why do I see slight speed changes? Playback speed is adjusted (0.85x-2.0x) to gradually correct drift without jarring seeks — imperceptible in most cases. See Sync Algorithms.
What if I’m several seconds behind? If drift exceeds 2.0 seconds, the client seeks directly instead of adjusting speed.
Does buffering affect sync? Yes, temporarily — the system waits for all clients to be “ready” before starting playback and continuously corrects drift afterward.
Technical
What ports are used? 8096 (Jellyfin) and 3000 (session server) by default.
What protocol is used? WebSocket with JSON messages — see Protocol.
Is the connection encrypted? It can be — use WSS with HTTPS. See Security.
How is authentication handled? Optional JWT tokens — see Security.
Getting Help
When reporting issues, include: your Jellyfin version, browser and OS, Docker version (if applicable), session server + plugin configuration (without secrets), reverse proxy setup, relevant logs (server/Jellyfin/browser console), and steps to reproduce.
- GitHub Issues - Bug reports
- GitHub Discussions - Questions
- Jellyfin Forums - Community help