All apps · 0 apps
emby-watchparty
Docker app from Mahesvara's Toolshed
Overview
Readme
View on GitHubEmby Watch Party
A synchronized watch-party frontend for Emby: watch together in sync while your Emby server stays on your internal network. Any member with Emby credentials can become the room's host; other viewers join as spectators without an account.
Table of contents
- Support development
- Special thanks
- Discord
- Documentation
- Features
- Browser compatibility
- Setup
- Usage
- Configuration
- Architecture
- API endpoints
- Troubleshooting
- Security notes
- License
- Contributing
- Acknowledgments
- Educational use notice
Support development
If Emby Watch Party has saved you from the hell of trying to coordinate "3, 2, 1, play" over Discord, consider buying me a coffee:
Every tip helps fund the hardware and the late nights reverse-engineering Emby's HLS pipeline.
Special thanks
Special thanks to QuackMasterDan for his dedication in testing and providing valuable feedback throughout development.
Thanks to wlowen and JeslynMcKenzie for testing, detailed bug reports, and providing mediainfo that helped track down the HEVC transcoding issues.
Thanks to @stealthydruid and @xyxxyxxy for the bug reports and feature requests on the Discord support server that shaped the late-stage 2.0 betas: APP_PREFIX healthcheck, A-Z library jump bar, image thumbnail sizing, resume from last position, jump-to-timestamp input, and the seek-bar tooltip thinking that got us there.
Discord
Documentation
- Project wiki - hardware, deployment, troubleshooting, and FAQ
- Migration guide - upgrade path for 1.x users moving to 2.0
- Socket.IO API - developer reference for the Socket.IO event protocol
- OpenAPI reference -
GET /docs(Swagger UI) orGET /redocon a running instance - CHANGELOG.md - per-release details including every fix and the reasoning behind it
- SUMMARY-OF-CHANGES.md - condensed release-by-release summary of the 2.0 betas
- Emby quirks we learned the hard way - Why 2.0 came to be.
Features
- Secure proxy architecture: your Emby server stays on the local network; only the WatchParty app is exposed
- FastAPI + Vue 3 + TypeScript stack: async end-to-end, typed OpenAPI docs at
/docsand/redoc, single uvicorn process serves backend + compiled SPA - Real-time sync with drift correction: selector-authoritative play/pause/seek against a party clock, keeping independent streams aligned
- Late-joiner voting flow: existing users vote to admit mid-playback joiners; a passing vote restarts on a PTS-aligned segment 0 so everyone lands together
- Host-provider auth model: UNLOCKED / PLAYING-ONLY / LOCKED lock states around the Emby-authenticated host, with a grace window for quick refreshes
- Per-user transcodes: every viewer gets their own Emby
PlaySessionId, so audio, subtitles, quality, and version are personal without disrupting the room - Multi-version playback: host-locked picker for items with multiple MediaSources (theatrical vs director's cut, mp4 vs mkv, 1080p vs 4K HDR)
- Bitrate-granular quality menu: mirrors Emby's own per-resolution table, with admin-side toggles for exposed resolutions and bitrates
- Unified subtitles: text subs via side-channel proxy, image (PGS) subs burned in per-user, both surfaced in one dropdown
- Resume, jump-to-timestamp, and binge auto-advance: Continue Watching prompt from Emby
UserData, absolute-timestamp seek input, and end-of-episode countdown with room-wide Cancel - Rooms, chat, and identity: 5-character party codes, live chat with a mobile slide-over, custom avatars (upload / Gravatar / monsterid fallback) recoverable via 3-word codes
- Refined Cyber UI: cyan/magenta/violet palette, glass surfaces, chip/pill controls, animated LIVE badge, iOS-style A-Z library jump bar
- Reverse-proxy ready:
APP_PREFIXwired end-to-end so one Docker image sits behind any subpath (https://example.com/watchparty/...) - Admin panel with hot-reload: runtime settings editable from
/adminas an in-party modal,.envreserved for boot-only keys - Reload-as-rejoin + healthchecks: refresh in an active party rejoins via persistent
client_id;/api/healthliveness for Docker/Kubernetes probes; rsyslog-style logging with rotation
Browser compatibility
Emby Watch Party works best with the following browsers:
Desktop
- Chrome - full support (recommended)
- Edge - full support (recommended)
- Firefox - full support
- Safari - full support
- Brave - full support
Mobile
- Safari (iOS) - full support with subtitles (recommended for iOS)
- Chrome (Android) - full support (recommended for Android)
- Brave (iOS) - video playback works, but subtitles do not appear in fullscreen mode
- Workaround: use Safari on iOS if you need subtitle support
Known issues
- Brave browser on iOS: subtitles work in normal view but disappear when entering fullscreen mode. This is a limitation of how Brave handles native video controls on iOS. Safari is recommended for iOS users who need subtitle support.
Setup
Prerequisites
- An Emby server (can be on local/internal network only; does not need to be exposed to the internet - the app acts as a secure proxy)
- An Emby admin API key (per-user Emby credentials are supplied at runtime via the in-app "Login to Become Host" flow, never in
.env) - The app must be reachable by your remote viewers - use a VPN such as Tailscale or Hamachi if you cannot port-forward
- For Docker installs (recommended): Docker 20.10+ (and optionally Docker Compose v2)
- For manual installs:
- Python 3.12 or higher (matches the runtime used in the official image)
- Node.js 20.19+ (or 22.12+) and npm - the Vue 3 frontend is a Vite build that must be produced before FastAPI can serve it
Manual installation
Docker (below) is the easier and recommended path - it bundles the frontend build and Python runtime for you. Only use manual installation if you specifically need to run against a local Python environment.
Build the frontend (Vite emits into
backend/static/, which FastAPI serves):cd frontend npm ci npm run build cd ..Install the Python backend dependencies:
pip install -r requirements.txtConfigure your settings. Copy
.env.exampleto.envand fill in at leastEMBY_SERVER_URL,EMBY_API_KEY, andSESSION_SECRET(generate withopenssl rand -hex 32):cp .env.example .envOnly boot-essential settings live in
.env- see.env.examplefor the full annotated list (bind/port,APP_PREFIX,SESSION_SECRET,SESSION_COOKIE_SECURE,CORS_ALLOWED_ORIGINS,EMBY_SERVER_URL,EMBY_API_KEY). All other runtime options (logging, rate limits, late-join vote,FORCE_TRANSCODE,REQUIRE_LOGIN, etc.) are managed live from the Admin Panel at/adminand persisted toconfig.json.Run the application from the repository root:
python -m backend.appOpen your browser and navigate to:
http://localhost:5000(If you set
APP_PREFIX=/watchparty, the app is served athttp://localhost:5000/watchparty/instead.)
Docker installation
The pre-built multi-arch image is published to GitHub Container Registry:
docker pull ghcr.io/oratorian/emby-watchparty:latest
Recommended: use the compose example. Copy docker-compose.yml.example to docker-compose.yml, copy .env.example to .env and fill in your Emby URL + API key, then:
# One-time: pre-create config.json so Docker does not create it as a
# directory on first `up`. Skip this and the backend will crash trying
# to write its settings.
touch config.json
docker compose up -d
The compose file mounts everything correctly out of the box. If you prefer docker run, the equivalent invocation is:
touch config.json
docker run -d \
--name emby-watchparty \
-p 5000:5000 \
--env-file .env \
-v "$(pwd)/data:/app/data" \
-v "$(pwd)/images/avatars:/app/images/avatars" \
-v "$(pwd)/config.json:/app/config.json" \
-v "$(pwd)/logs:/app/logs" \
ghcr.io/oratorian/emby-watchparty:latest
Required mounts (avatars and runtime config will be wiped on container recreation without them):
| Host path | Container path | Purpose |
|---|---|---|
./data |
/app/data |
SQLite avatar DB (avatars.db) |
./images/avatars |
/app/images/avatars |
Uploaded avatar image files |
./config.json |
/app/config.json |
Runtime admin settings (edited via /admin) |
Optional mount:
| Host path | Container path | Purpose |
|---|---|---|
./logs |
/app/logs |
Application logs (only written when LOG_TO_FILE is enabled in /admin; console-only by default) |
SESSION_SECRET is new in 2.0.0-beta18: it's the signing key for the party-bound session cookie. Set it once (openssl rand -hex 32) and leave the value stable across restarts and across every uvicorn worker. When unset, an ephemeral key is generated at boot with a loud warning - every restart kicks all users out of their party, and multi-worker deploys become non-deterministic per request. Pair with SESSION_COOKIE_SECURE=true on any HTTPS deployment and pin CORS_ALLOWED_ORIGINS to your real origin(s) (the historical * default remains for backwards compat). Full block in .env.example.
Config split (2.0): .env is boot-only (~6 keys: bind/port, Emby URL/key, session hardening). All other settings - including LOG_TO_FILE, transcoding options, feature toggles - live in config.json and are edited from the admin panel at /admin. Do not try to set them as environment variables; they will be ignored.
Usage
Creating a watch party
The default (REQUIRE_LOGIN=false):
- Click "Create Party" on the home page (no login required)
- Share the party code or URL with your friends
- Inside the party, click "Login to Become Host" with your Emby credentials -- this unlocks the library for everyone in the room. Any party member with an Emby account can do this; spectators never see a login prompt.
- Browse the library and select a video
- Everyone in the room will be synchronized
With REQUIRE_LOGIN=true (set from the admin panel):
- Click "Create Party" -- you will be prompted for Emby credentials
- The creator becomes host atomically; the party starts UNLOCKED
- Share the code; spectators join with no login prompt
- Browse, pick, watch
In both modes, when the host disconnects mid-playback the in-flight video keeps streaming until it ends naturally (PLAYING-ONLY state). The library re-locks immediately; any member can click "Login to Become Host" to unlock it again.
Joining a watch party
- Click "Join Watch Party" on the home page (or open a shared URL)
- Enter the party code if needed
- Enter your username
- Start watching together!
If you join before a video has been selected, you land directly in the party. If you join while a video is already playing, the existing users will see a vote modal asking whether to restart the video from the beginning so you can join in sync. See the project wiki for full details of the late-joiner vote flow.
In-party controls
- Browse library: use the sidebar to browse your Emby libraries, movies, and TV shows
- Select video: click on any video to start watching it with the group
- Video controls: any user can play, pause, or seek - all users will sync
- Audio, subtitles, quality: each user can pick their own settings independently. If the party is paused, the change is silent; if the party is playing, everyone briefly pauses while the new stream loads so you do not desync
- Chat: use the chat box at the bottom to communicate with other viewers
- Leave: click the "Leave" button to exit the watch party
Configuration
Configuration is split into two tiers:
- Boot-essential settings live in
.envand require a server restart to change. Copy.env.exampleto.envand set these before starting the service. - Runtime settings are editable from the admin panel at
/admin(Emby administrator credentials required) and are hot-reloadable -- no restart needed.
.env
Boot-essential, restart required.
| Variable | Description | Default |
|---|---|---|
| Application | ||
WATCH_PARTY_BIND |
IP address to bind to | 0.0.0.0 |
WATCH_PARTY_PORT |
Port to run on | 5000 |
APP_PREFIX |
URL prefix for reverse proxy deployments (e.g. /watchparty) |
(empty) |
SESSION_EXPIRY |
Session expiry in seconds | 86400 |
| Session cookie (new in 2.0.0-beta18) | ||
SESSION_SECRET |
Signing key for the party-bound session cookie. Generate ONCE with openssl rand -hex 32 and leave it. Empty = ephemeral random per boot with a loud warning (every restart kicks users out; multi-worker deploys are non-deterministic). |
(generated) |
SESSION_COOKIE_SECURE |
When true, the session cookie carries the Secure flag (HTTPS-only). Set true in every deployment behind TLS; leave false for http://localhost dev. |
false |
| Socket.IO CORS (new in 2.0.0-beta18) | ||
CORS_ALLOWED_ORIGINS |
Comma-separated origin allowlist for the Socket.IO server (https://a.example.com,https://b.example.com). * accepts any origin (historical default). Pin to your real origin(s) in production. |
* |
| Emby server | ||
EMBY_SERVER_URL |
Your Emby server URL | http://localhost:8096 |
EMBY_API_KEY |
Emby API key (server admin key) | (required) |
REQUIRE_LOGIN was previously here. It now lives in the admin panel as a runtime, hot-reloadable setting; see the host-provider authentication model in Architecture for the full semantics.
Admin panel
Runtime, hot-reloadable. All of the following settings are editable at /admin. See the project wiki for a walkthrough.
Logging
| Setting | Description | Default |
|---|---|---|
| Log level | Application log verbosity (DEBUG, INFO, WARNING, ERROR) | INFO |
| Console log level | Terminal output verbosity | WARNING |
| Log to file | Write logs to disk | true |
| Log file | Path to log file | logs/emby-watchparty.log |
| Log format | rsyslog or standard |
rsyslog |
| Max log size (MB) | Rotation threshold | 10 |
Security
| Setting | Description | Default |
|---|---|---|
| Max users per party | 0 = unlimited | 0 |
| HLS token validation | Prevent direct stream access bypass | true |
| HLS token expiry (s) | Token lifetime | 86400 |
| Rate limiting | Enable API rate limiting | true |
| Party creation limit | Max per IP | 5 per hour |
| API rate limit | Max per IP | 1000 per minute |
Session
| Setting | Description | Default |
|---|---|---|
| Static session mode | Auto-create a fixed party on startup | false |
| Static session ID | Party code when static mode is enabled | PARTY |
Late join vote (new in 2.0)
| Setting | Description | Default |
|---|---|---|
| Enable late join vote | Require a majority vote to admit users who join mid-playback | true |
| Vote timeout (s) | Seconds before the selector tiebreak kicks in | 20 |
| Post-vote cooldown (s) | Delay after a failed vote before another join attempt is allowed (0 disables) | 30 |
Architecture
Backend (FastAPI + python-socketio)
- FastAPI: async REST API, dependency-injected components, Pydantic schemas for every request/response body (
backend/src/schemas.py). - python-socketio
AsyncServer(ASGI mode) mounted underAPP_PREFIX/socket.io: WebSocket-based real-time sync, hardened with a 128 KiB frame cap and tightened ping timings. - httpx: async HLS proxy - the backend streams
.m3u8/.ts/.vttsegments from Emby on the user's behalf so the Emby server never sees the public internet. - uvicorn ASGI worker, bound to
WATCH_PARTY_BIND:WATCH_PARTY_PORT. - HLS.js-compatible playlists: token-gated (
HLSTokenManager) short-lived URLs prevent segment scraping.
Frontend (Vue 3 + TypeScript)
- Vue 3 SPA authored in TypeScript, bundled with Vite (base
./for prefix-agnostic asset resolution). - Pinia stores for auth, party, playback, and socket state; Vue Router for
/party/:code,/admin, and landing routes. - socket.io-client for the sync channel, axios for REST, hls.js for adaptive playback.
Per-user transcode model
Each viewer gets their own PlaySessionId and a fresh Emby transcode session built by StreamBuilder. Seeks, quality changes, and disconnects only affect the individual user's stream - the party's shared clock stays authoritative, and Emby's stop_active_encodings is called on every disconnect to reap the transcode.
Host-provider authentication
There is no application user database. Any party member can promote themselves to host by authenticating with Emby credentials from inside the party (POST /api/auth/login). The resulting AccessToken lives in RAM only on the PartyManager party record and is never persisted or sent to clients. When the host disconnects, a 5-second grace timer starts; a refresh/reconnect during that window silently reclaims host. If the timer expires, the party transitions through a three-state lock:
- UNLOCKED - host present, all playback and library browsing allowed.
- PLAYING-ONLY - host gone mid-playback; the in-flight token is retained so viewers can finish the current video, but no new playback or seeks may start.
- LOCKED - host gone with no active video; token cleared, party waits for someone to log in as the new host.
Key components
PartyManager- party lifecycle, sid <-> client_id mapping, host state machine, ready-check and late-join vote bookkeeping.EmbyClient- thin async wrapper around Emby's REST API (auth, items, playback reporting, encoding teardown).HLSTokenManager- mints and validates short-lived per-user HLS URL tokens.StreamBuilder- assembles per-user transcode URLs, honouring theFORCE_TRANSCODEadmin toggle.AvatarStore- SQLite-backed avatar metadata plus a sibling images directory (both Docker-mountable).
Deployment
Ships as a single multi-stage Docker image: a Node stage runs npm run build to produce the Vue bundle, then a Python stage installs backend dependencies and copies the built static/ into the FastAPI app. One container, one port, one process - uvicorn serves the API, the SPA, and the WebSocket mount under the configurable APP_PREFIX.
API endpoints
Emby Watch Party 2.0 ships a FastAPI backend (REST + OpenAPI) and a Socket.IO real-time surface. Rather than duplicate the full spec here, the canonical references are:
- REST / OpenAPI: interactive docs at
/docs(Swagger UI) and/redocwhen the backend is running. - Socket.IO:
docs/SOCKET_API.md- every inbound / outbound event, payload shapes, and the multi-step flows.
REST API (representative endpoints)
The FastAPI app is composed of nine routers under backend/src/routers/. A small sample:
auth-POST /api/auth/login(Emby login, host-claim),POST /api/auth/logoutparty-POST /api/party/create,POST /api/party/{id}/join,GET /api/party/{id}/infolibrary-GET /api/libraries,GET /api/items?parentId=...,GET /api/item/{item_id}media-GET /api/media/{item_id}/streams,GET /api/media/{item_id}/versionshls-GET /api/hls/{session}/master.m3u8, segment + subtitle proxy passthroughquality-GET /api/quality/profiles,GET /api/quality/defaultavatar-POST /api/avatar/upload,GET /api/avatar/{uuid}admin-GET/PUT /api/admin/config,POST /api/admin/party/{id}/dissolvehealth-GET /api/health,GET /api/version
See /docs for the full parameter, response, and auth-scope details.
WebSocket events (Socket.IO)
Mounted under ${APP_PREFIX}/socket.io. Events group into these categories:
- Connection lifecycle -
connect/disconnect/connected, transparent reconnect via stableclient_id. - Party join / leave / vote -
join_party,leave_party,user_joined/user_left, plus the late-joiner vote (join_vote,join_vote_started,join_vote_update,join_vote_resolved,join_rejected). - Host state -
host_changed,host_left,host_reclaimed, three-state lock (UNLOCKED / PLAYING-ONLY / LOCKED). - Playback -
select_video,stop_video,change_streams(per-user),play,pause,seek,video_selected,streams_changed,video_stopped,video_ended. - Sync coordination -
stream_ready,ready_check_update,all_ready,force_pause_before_seek,heartbeat+drift_correction,report_progress. - Chat / UI -
chat_message,toggle_library,update_avatar+members_update,sync_state. - Binge-watch / auto-advance -
set_binge_watch_active,binge_watch_state_changed,auto_advance_pending,auto_advance_cancel(led),auto_advance_fired,binge_finished. - Admin / errors -
party_dissolved,error.
Full payloads, auth requirements, and flow diagrams live in docs/SOCKET_API.md.
Troubleshooting
Common issues and fixes are catalogued on the wiki: Troubleshooting.
Quick checks before opening an issue:
- App unreachable. Confirm the backend is bound on
WATCH_PARTY_BIND/WATCH_PARTY_PORTand that clients can reach it. Behind a reverse proxy, verifyAPP_PREFIXmatches the mount path and that WebSocket upgrades are forwarded. - Can't browse or play media. The admin
EMBY_API_KEYin.envmust be valid, and the Emby server (EMBY_SERVER_URL) must be reachable from the backend. To play, someone in the party has to click Login to Become Host and supply their own Emby credentials - nothing plays until a host provider is attached. - Playback works, sync doesn't. Confirm the Socket.IO transport isn't being downgraded or blocked by an intermediate proxy, and that
CORS_ALLOWED_ORIGINSincludes your real origin. - Session cookie rejected / kicked out on every restart.
SESSION_SECRETmust be set to a stable value (openssl rand -hex 32). An unset secret regenerates on boot and invalidates every existing cookie; with--workers >1each worker signs differently. - Logs. Logging goes to stdout by default. File logging is opt-in from /admin -> Logging; the log path shown there is where to look once enabled.
Security notes
- Proxy architecture. The Emby server stays on your internal network. All HLS segments and playlists are pulled by the backend and re-served to clients, so browsers never talk to Emby directly.
- Credential model.
.envholds only the adminEMBY_API_KEY, used for library browsing and administrative Emby calls. Do not commit.env.- Per-user Emby credentials are never persisted. Any party member can click Login to Become Host in-app and authenticate against Emby; the resulting AccessToken lives in memory as that party's host provider and is used to open per-user transcode sessions. Tokens are discarded when the host provider changes or the party ends.
- Session secret.
SESSION_SECRETsigns the party-bound session cookie and must be stable across restarts and across every uvicorn worker - generate once withopenssl rand -hex 32. An unset secret produces an ephemeral key at boot (loud warning), which invalidates cookies on every restart and produces non-deterministic sessions under--workers >1. - HLS URLs. Since beta18, HLS playlist and segment URLs served to the browser no longer carry the admin
EMBY_API_KEYas a query parameter. Access is gated by a per-stream HLS token bound to the session cookie; the API key stays server-side. - Party codes are generated with cryptographically secure random tokens.
- Built-in controls. HLS token validation, per-IP rate limiting, and configurable party size limits are on by default; tune them in /admin -> Security.
- For internet-facing deployments, terminate TLS at a reverse proxy (nginx, Caddy, Traefik), set
SESSION_COOKIE_SECURE=true, and pinCORS_ALLOWED_ORIGINSto your real origin(s) instead of*.
License
MIT License - feel free to modify and use as you wish.
Contributing
Contributions welcome. See CONTRIBUTING.md for branch conventions, PR flow, and coding guidelines. Issues and feature requests go in GitHub Issues.
Wiki edits are open - if you deploy on hardware or a platform not yet documented, please add your findings.
Acknowledgments
- Integrates with Emby Media Server
- UI design: Refined Cyber by Christian Gillinger
- The community testers on Discord who lived through every beta and kept filing the bug reports that made 2.0 what it is
Educational use notice
This project is intended for educational purposes and private use only. Please ensure you use this responsibly and in compliance with your Emby server's terms of service and applicable copyright laws.
Install emby-watchparty on Unraid in a few clicks.
Find emby-watchparty in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Requirements
Related apps
Explore more like this
Explore allDetails
ghcr.io/oratorian/emby-watchparty:latestRuntime arguments
- Web UI
http://[IP]:[PORT:5000]- Network
bridge- Shell
sh- Privileged
- false
Template configuration
Host port for the emby-watchparty web interface. Must match WATCH_PARTY_PORT below.
- Target
- 5000
- Default
- 5000
- Value
- 5000
Full URL to your Emby server, e.g. http://192.168.1.100:8096. Reachable from inside this container.
- Target
- EMBY_SERVER_URL
- Default
- http://192.168.1.x:8096
- Value
- http://192.168.1.x:8096
Admin Emby API key. Generate one in Emby Dashboard > Advanced > API Keys. Per-user credentials are NOT set here -- users log in from inside the party UI.
- Target
- EMBY_API_KEY
Signing key for the party-bound session cookie. Generate ONCE with `openssl rand -hex 32` and leave it -- must persist across restarts and across every uvicorn worker. If left at the default, an ephemeral key is generated at boot with a loud warning; fine for local dev, catastrophic in production (every restart kicks everyone out).
- Target
- SESSION_SECRET
- Default
- change-me-openssl-rand-hex-32
- Value
- change-me-openssl-rand-hex-32
When `true`, the session cookie carries the Secure flag so browsers only send it over HTTPS. Set `true` for every deployment behind TLS; leave `false` for local http://localhost dev (setting it true on an http origin locks users out).
- Target
- SESSION_COOKIE_SECURE
- Default
- false
- Value
- false
Interface the app listens on inside the container. 0.0.0.0 listens on all interfaces (typical for Docker); rarely needs changing.
- Target
- WATCH_PARTY_BIND
- Default
- 0.0.0.0
- Value
- 0.0.0.0
Port the app binds inside the container. Must match the container-side of the Web UI Port mapping above.
- Target
- WATCH_PARTY_PORT
- Default
- 5000
- Value
- 5000
URL prefix for reverse-proxy deployments behind a subpath (e.g. /watchparty). Leave empty for root-of-domain deployments. Backend routers, Socket.IO, /assets, and the SPA all honour the prefix at runtime -- no rebuild required.
- Target
- APP_PREFIX
Comma-separated origin allowlist for the Socket.IO server. `*` accepts XHR-poll handshakes from any origin -- convenient for testing but pair with per-IP throttling. Pin to your real origin(s) for a proper deployment, e.g. `https://watchparty.example.com,https://staging.example.com`.
- Target
- CORS_ALLOWED_ORIGINS
- Default
- *
- Value
- *
Session cookie lifetime in seconds. Default 86400 (24 hours).
- Target
- SESSION_EXPIRY
- Default
- 86400
- Value
- 86400
Persists the avatars.db SQLite database. Without this mount, every container recreate wipes every member's chosen avatar.
- Target
- /app/data
- Default
- /mnt/user/appdata/emby-watchparty/data
- Value
- /mnt/user/appdata/emby-watchparty/data
Persists uploaded avatar image files. Paired with the Avatar Database mount above.
- Target
- /app/images/avatars
- Default
- /mnt/user/appdata/emby-watchparty/avatars
- Value
- /mnt/user/appdata/emby-watchparty/avatars
Persists the runtime admin config (edited via /admin) across container recreates. IMPORTANT: `touch config.json` on the host BEFORE the first start, otherwise Docker silently creates it as an empty DIRECTORY and the backend fails to write.
- Target
- /app/config.json
- Default
- /mnt/user/appdata/emby-watchparty/config.json
- Value
- /mnt/user/appdata/emby-watchparty/config.json
Optional: persist application logs to disk. Only writes when Log To File is enabled in the /admin panel (default: console-only).
- Target
- /app/logs
- Default
- /mnt/user/appdata/emby-watchparty/logs
- Value
- /mnt/user/appdata/emby-watchparty/logs