Watch together, decide together.
Gogglebox is a LAN-first Jellyfin frontend for people who want the best possible experience choosing and watching something as a party. It treats the room as the important unit: pick who is watching, see what makes sense for that set of people, and hand off playback to Jellyfin without turning movie night into admin work.
Jellyfin remains the source of truth for media, metadata, and watch history. Gogglebox sits in front of it as a focused, party-aware layer for shared selection, shared progress, and a smoother path from "what should we watch?" to "press play."
Users are referenced by their (unique) Jellyfin name in config.json; Gogglebox
resolves names to ids itself at startup. One or more login accounts each see only
the users they are allowed to, and parties are formed live in the UI (a party is a
Jellyfin user created on demand). Parties were formerly called "groups" — the
server still accepts the old /api/group* routes and response fields as
compatibility aliases (see src/server/server.ts). Jellyfin remains the source
of truth for library, metadata, and watch history; Gogglebox is a thin
party-aware layer on top.
When enabled by feature flag, the main discovery surface deals a finite Tonight's Nine set for the active party and shows it as three large cards: the selected card in the middle with readable neighbors on either side. The room can move focus, register lightweight positive sentiment, dismiss a pick for tonight, start a short play countdown, or hold play to launch the focused item immediately.
The work backlog lives under efforts. Current top-level efforts include
authentication, persistence, show-detail browsing, and the v2026.8.29
"Judgement Day" discovery work.
Judgement Day is the main product direction: fact-driven, explainable recommendations for the whole room, presented as "Tonight's Nine": a finite set of nine session picks shown through three large, couch-readable cards with a slight center focus. Recommendation channels contribute weighted evidence to the same item ids, so party resume, party next-up, newly added, party-seen, and library quality can all reinforce the same movie, episode, or show without needing separate ranking machinery. Controller-first input remains the target: quick play starts a short countdown, hold play starts the focused item immediately, and explicit up/down sentiment teaches the system without exposing individual watch-progress history. Planned work is described in the effort specs.
Gogglebox is meant to be simple to run on a LAN. A deployment host needs Docker Compose, git, access to your Jellyfin server, and a small amount of local config. The published image is served behind Caddy so the browser reaches one origin:
/for the Gogglebox client/api/*for the Gogglebox server/player/*for Jellyfin Web
That single origin is what lets Gogglebox prepare the Jellyfin player handoff.
Clone the repo on the machine that will host Gogglebox:
git clone <repo-url>
cd goggleboxCopy and edit the deploy config:
cp deploy/config.example.json deploy/config.json
cp deploy/.env.example deploy/.envIn deploy/config.json, configure schemaVersion 2 auth: list the Jellyfin users
Gogglebox may show, define one or more household accounts, and map login tokens
to those accounts. Use Jellyfin user names, not UUIDs. Older supported config
shapes are migrated automatically by the app on startup.
In deploy/.env, set the required deployment values:
| Var | Purpose |
|---|---|
GOGGLEBOX_PORT |
Host port for the Gogglebox front door |
JELLYFIN_URL |
Normal Jellyfin origin, without /player |
JELLYFIN_API_KEY |
Jellyfin API key |
SESSION_SECRET |
Long random string for session cookies |
ACCESS_TOKEN is optional. When set to a token that exists in
deploy/config.json, Gogglebox automatically logs the browser into that token's
account and skips the token form. Leave it unset when you want visitors to type
their token.
Start Gogglebox from the repo root:
docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -dOpen http://<host>:<GOGGLEBOX_PORT>.
The deployment compose starts a private GO Feature Flag sidecar next to the app.
Gogglebox calls it internally and exposes only the app-owned /api/flags
contract to the browser. The sidecar reads flags/goff.yaml, where
tonights-nine is production-safe disabled by default; changing that file can
update flag state without rebuilding the Gogglebox image.
Useful deploy commands:
docker compose -f deploy/docker-compose.yml --env-file deploy/.env ps
docker compose -f deploy/docker-compose.yml --env-file deploy/.env logs -f
docker compose -f deploy/docker-compose.yml --env-file deploy/.env downRuntime state, such as ignored items, is stored under the configured state
directory. For a real deployment, set GOGGLEBOX_STATE_DIR to a durable host
path that is writable by container uid 1000.
Gogglebox login is token-only. A visitor enters one access token; that token maps
to an account key in access_tokens, and the account controls which Jellyfin
users the visitor can select. There is no separate username/password portal
login in the current config model.
{
"schemaVersion": 2,
"users": [
{ "jellyfin_name": "Alice", "pin": "1234" },
{ "jellyfin_name": "Bob" },
{ "jellyfin_name": "Carol", "pin": "5678" }
],
"accounts": {
"living_room": {
"primary_users": ["Alice"],
"secondary_users": ["Bob"],
"tertiary_users": ["Carol"]
}
},
"access_tokens": {
"replace-with-a-long-random-token": "living_room"
}
}After a successful manual token login, the browser remembers the token in local
storage and uses it on later visits until Log out is clicked. This is separate
from ACCESS_TOKEN auto-login, which is configured on the server and applies to
any browser reaching that deployment.
Account tiers control the picker:
primary_usersare selected by default when the account opens Gogglebox.secondary_usersare shown as normal selectable viewers, but are not selected by default.tertiary_usersare guests. They are hidden behind Add guest and require the configured user PIN whenever they are added to a party for that account.
If secondary_users or tertiary_users is omitted or set to null, it acts as
a wildcard over the remaining live Jellyfin users after higher-priority tiers
are assigned. Guests without a configured pin in users are not addable,
because Gogglebox cannot verify them.
Development also runs through Docker Compose. The host should not need Node,
npm, or a host node_modules; dependencies live in Docker volumes.
The base compose file is for checks that do not need Jellyfin:
docker compose run --rm check
docker compose run --rm test
docker compose downTo run the full app, use one of the wrapper stacks:
| Stack | Purpose |
|---|---|
./scripts/sbx.sh |
Seeded offline sandbox Jellyfin for repeatable local work |
./scripts/uat.sh |
A developer's real Jellyfin for user-acceptance testing |
Both stacks serve the app through http://localhost:8080 with /api routed to
Gogglebox and /player routed to Jellyfin. The server and client services do
not expose separate host ports.
Local and sandbox stacks also run the GO Feature Flag sidecar. By default it
mounts flags/goff.yaml; set GOFF_FLAGS_FILE to another complete GOFF file
when a proof needs a different flag state.
Common examples:
./scripts/sbx.sh up -d
PROOF_FLOW=mark-all-watched ./scripts/sbx.sh run --rm proof
./scripts/uat.sh up -d
PROOF_FLOW=continue-watching ./scripts/uat.sh run --rm proofSee the agent guide for the agent workflow and the Docker-specific rules that keep local development consistent.
Images are published to ghcr.io/sycdan/gogglebox. Maintainers use the repo's
versioning and publish scripts/workflows to build once, test once, and promote a
tested image to a release tag. Deployers can pin GOGGLEBOX_VERSION in
deploy/.env when they want reproducible upgrades and rollbacks.
Gogglebox is a self-hosted companion interface for Jellyfin. It does not provide, host, index, download, rip, decrypt, or distribute media.
You are responsible for ensuring that your Jellyfin server, media library, user access, network exposure, and any sharing you configure comply with applicable law and with the rights associated with your media. Do not use Gogglebox to make copyrighted works available to others unless you have the right to do so.
Gogglebox is intended for lawful personal and household use with media you are authorized to access.
In loving memory of Oggie.