Troubleshooting & FAQ

Quick Diagnostic Checklist

  1. Session server running? (curl http://localhost:3000/health)
  2. Plugin installed? (Check Dashboard > Plugins)
  3. Script tag in Custom HTML? (Dashboard > General) — or is file-transformation installed?
  4. Browser cache cleared? (Ctrl+F5)
  5. Correct WebSocket URL configured?
  6. Firewall allowing the session server port (default 3000)?
  7. 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

  1. Check Custom HTML configuration — Dashboard > General > Branding should have:
    <script src="../JellyWatchParty/ClientScript"></script>
    
  2. Hard refresh the browser (Ctrl+F5 / Cmd+Shift+R), or clear the cache completely
  3. Check browser console (F12) — a 404 means the script wasn’t found (plugin not installed); a CORS error means the WebSocket was blocked (check CORS config)
  4. Verify plugin is installed — Dashboard > Plugins should show “JellyWatchParty”; check Jellyfin logs for plugin load errors
  5. On Jellyfin 12, update to the latest JellyWatchParty release — versions before the Jellyfin 12 UI fix only checked whether .headerRight existed, 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.
  6. 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.
  7. 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

  1. Check server is running: docker ps | grep session and curl http://localhost:3000/health
  2. Check firewall: nc -zv localhost 3000, open the port if needed (sudo ufw allow 3000/tcp)
  3. Check the WebSocket URL — browser console shows the attempted URL; should be ws://host:3000/ws or wss://host:3000/ws
  4. Check CORS — session server logs show CORS errors; set ALLOWED_ORIGINS to include your Jellyfin URL

Sync Issues

Participants out of sync, playback drifting apart, or frequent jumping/stuttering:

  1. Wait a few seconds — initial sync takes 2-3 seconds and drift correction is gradual by design
  2. Host: pause and play again to re-sync everyone
  3. Check network quality — high latency causes sync issues; check RTT in the panel (ideal < 100ms)
  4. HLS/transcoding — transcoded streams have higher latency; try direct play or reduce quality if network is slow
  5. 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

  1. Check JWT configuration matches — plugin JWT Secret must match server JWT_SECRET; both must be configured or both must be empty
  2. Check token expiration — default 1 hour; refresh the page for a new token
  3. Rate limiting — max 10 token requests per minute; wait and try again
  4. 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 with openssl 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 readyState differently 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:

  1. /jwp doesn’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 the applications.commands scope. After you save the Server ID, allow up to 30 seconds. If it still doesn’t appear, check docker logs jwp-discord-bot.
  2. “Watch parties from chat are turned off on this server”. Bot enabled is off in the admin panel.
  3. The chip reads “No bot token” or “Bot offline”. Run docker ps and check that jwp-discord-bot is up. It only starts with --profile discord. Both containers need the same token: the session server’s DISCORD_INTEGRATION_TOKEN and the bot’s JWP_INTEGRATION_TOKEN. The token must be at least 32 characters (openssl rand -hex 32). If Discord rejects DISCORD_BOT_TOKEN, the bot log says Discord connection ended for good (bad token or intents?).
  4. The session server logs Chat integrations: NOT started - .... The reason follows the dash. Common causes: DATA_DIR is unset (the compose files set /data); DISCORD_INTEGRATION_TOKEN is missing or too short; INTEGRATION_HOST is a name rather than an IP address (localhost is not accepted); INTEGRATION_PORT equals PORT or ADMIN_PORT. The bot also needs the admin panel running (ADMIN_PASSWORD set, ADMIN_ENABLED not false) and the Jellyfin devices settings (JELLYFIN_URL, JELLYFIN_API_KEY).
  5. The bot’s JWP_INTEGRATION_URL can’t reach the session server. The bot’s default is http://session-server:3002. The quick-start compose uses jwp-session, which sets the URL explicitly. If you changed INTEGRATION_PORT, the URL must change too.
  6. 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.
  7. 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.
  8. /jwp device add says “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.
  9. “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.
  10. 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.
  11. Codes stop working after you move or restore the data. The secret.key file in DATA_DIR is missing or was replaced. A new key is created silently, and every existing code stops matching. Restore the whole jwp-data volume, 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.


Back to top

JellyWatchParty - Synchronized watch parties for Jellyfin