Note: This project is currently in beta/work-in-progress. Features may change and bugs are expected. Feedback and contributions are welcome!
A film voting platform for movie nights that integrates with your Plex ecosystem. Vote on movies, track who's watched what, and organize recurring movie nights with friends.
| Dashboard | Group | Movie Night |
|---|---|---|
![]() |
![]() |
![]() |
- Plex OAuth authentication
- Import Plex users and create local users for guests
- Create groups for different friend circles
- Recurring and one-off movie night schedules
- Nominate movies via Overseerr or TMDB search
- Vote on nominations with watch history tracking via Tautulli
- Guest access via shareable invite links
- Host assignment with veto power
- Attendance tracking
- Docker
- Plex Media Server with Plex Pass (for OAuth)
- Overseerr or TMDB API key (for movie search) - optional
- Tautulli (for watch history) - optional
docker run -d --name voterr -p 5056:5056 -v ./voterr-data:/app/data tmirage/voterr:latestOpen http://localhost:5056 and complete the setup wizard to configure Plex and other services.
- Go to Tautulli Settings
- Navigate to Web Interface
- Copy the API Key
- Go to Overseerr Settings
- Navigate to General
- Copy the API Key
- Create account at themoviedb.org
- Go to Settings > API
- Request an API key
- Node.js 20+
- npm
# Install dependencies
npm install
cd client && npm install && cd ..
# Start development servers
npm run devThis starts the frontend dev server with hot reload on http://localhost:5173, which proxies API requests to the backend on port 5056.
In production (Docker), the backend serves the built frontend directly on a single port.
voterr/
├── client/ # React frontend
│ ├── src/
│ │ ├── components/ # Reusable components
│ │ ├── context/ # React context (auth)
│ │ ├── lib/ # Utilities (API client)
│ │ └── pages/ # Page components
│ └── ...
├── server/ # Express backend
│ ├── db/ # Database setup
│ ├── middleware/ # Express middleware
│ ├── routes/ # API routes
│ └── services/ # External service integrations
├── data/ # SQLite database (created at runtime)
├── docker-compose.yml
├── Dockerfile
└── package.json
GET /api/auth/plex- Initiate Plex OAuthGET /api/auth/plex/callback- Check Plex auth statusGET /api/auth/me- Get current userPOST /api/auth/logout- Logout
GET /api/users- List all usersGET /api/users/plex-friends- Get importable Plex friendsPOST /api/users/import-plex- Import a Plex userPOST /api/users/local- Create a local userDELETE /api/users/:id- Delete a user
GET /api/groups- List user's groupsGET /api/groups/:id- Get group detailsPOST /api/groups- Create a groupPOST /api/groups/:id/members- Add membersDELETE /api/groups/:id/members/:userId- Remove memberDELETE /api/groups/:id- Delete group
GET /api/schedules/group/:groupId- List group schedulesPOST /api/schedules- Create a scheduleDELETE /api/schedules/:id- Delete a scheduleGET /api/schedules/movie-nights/group/:groupId- List movie nightsGET /api/schedules/movie-nights/:id- Get movie night detailsPATCH /api/schedules/movie-nights/:id- Update movie nightPOST /api/schedules/movie-nights/:id/attendance- Set attendance
GET /api/movies/library- Get movies from OverseerrGET /api/movies/search?q=term- Search moviesGET /api/movies/:tmdbId- Get movie details
GET /api/votes/movie-night/:id- Get nominations with votesPOST /api/votes/nominate- Nominate a movieDELETE /api/votes/nominations/:id- Remove nominationPOST /api/votes/vote- Vote for a nominationDELETE /api/votes/vote/:nominationId- Remove votePOST /api/votes/movie-night/:id/decide- Pick winner (host/admin)
POST /api/invites/create- Create guest invite linkGET /api/invites/validate/:token- Validate invitePOST /api/invites/guest-login- Login as guest via inviteGET /api/invites/movie-night/:id- List invites for movie nightDELETE /api/invites/:id- Delete invite
| Variable | Description | Default |
|---|---|---|
PORT |
Server port | 5056 |
TZ |
Timezone | Europe/Amsterdam |
All settings (Plex, Tautulli, Overseerr, TMDB) are configured through the web UI. Session secrets are auto-generated and stored in the database.
- Session secrets are auto-generated on first run and stored in the database
- Cookies automatically use
secure: truewhen accessed via HTTPS (auto-detected viaX-Forwarded-Protoheader) - All API endpoints require authentication except health check and setup status
- CSRF protection on all POST/PUT/DELETE requests
- Rate limiting on invite link validation (5 requests/minute per IP)
- Rate limiting on PIN attempts (5 failures = 1 minute lockout per IP)
- Groups can require a 6-digit PIN for invite links
- Local invite users can only access their specific movie night
- Image uploads restricted to authenticated non-guest users
- All SQL queries use parameterized statements (no SQL injection)
docker run -d \
--name voterr \
-p 5056:5056 \
-v ./voterr-data:/app/data \
tmirage/voterr:latestThat's it! Open http://localhost:5056 and complete the setup wizard to configure Plex and other services.
services:
voterr:
image: tmirage/voterr:latest
container_name: voterr
restart: unless-stopped
ports:
- "5056:5056"
volumes:
- ./voterr-data:/app/dataThe Docker image is built for multiple platforms:
linux/amd64- Standard x86_64 serverslinux/arm64- Raspberry Pi 4, Apple Silicon, ARM servers
MIT


