More'Wax is a self-hosted web app for managing your vinyl record collection. It runs a Python server on your computer and serves a responsive web UI you open in any browser β desktop or mobile. Records can be added by barcode scan, cover photo identification (via Claude Vision), or manual Discogs search. Prices are fetched from the Discogs marketplace and new additions are automatically synced to your Discogs account.
A Discogs personal access token is required β More'Wax uses your Discogs account to search releases, fetch prices, and sync your collection.
An Anthropic API key is optional β only needed for photo-based cover identification (Claude Vision). Barcode scanning and manual search work without it. Each photo identification costs $0.007 with Claude Sonnet ($0.70 per 100 photos).
docker run -d \
--name more-wax \
-p 8765:8765 -p 8766:8766 \
-v morewax-data:/app/data \
eboudrant/more-wax:latestDocker Desktop users: Use the command above, not the "Run" button β Docker Desktop does not map ports automatically without the
-pflags.
docker compose up -dpython3 server.pyOpen https://localhost:8766 and accept the self-signed certificate. A setup wizard will guide you through connecting your Discogs account and optionally enabling Claude Vision for cover photo identification.
On mobile, use https://<your-ip>:8766. Camera features (barcode scan, photo) require HTTPS β on plain HTTP only collection browsing is available.
Press Ctrl+C to stop the server.
API tokens (Discogs, Anthropic) are configured through the in-app setup wizard on first launch. They are saved to data/.env and persist across restarts.
You can also set configuration via environment variables (these override the wizard values):
| Variable | Required | Description |
|---|---|---|
DISCOGS_TOKEN |
Yes | Discogs personal access token (get one here) |
ANTHROPIC_API_KEY |
No | Anthropic API key for cover photo identification (get one here) |
VISION_MODEL |
No | Claude model for cover identification (default: claude-sonnet-4-6) |
HTTP_PORT |
No | HTTP port (default: 8765) |
HTTPS_PORT |
No | HTTPS port (default: 8766) |
More'Wax follows a fat server / thin client architecture. All API tokens, business logic, and external service calls live on the Python backend. The browser client is pure UI β it knows nothing about Discogs credentials or Claude API keys.
graph LR
Browser["π Browser<br/><small>static/js/ β Pure UI<br/>No tokens or secrets</small>"]
Server["π Python Server<br/><small>server/ β Business logic<br/>JSON file storage</small>"]
Discogs["πΏ Discogs API"]
Anthropic["π€ Claude API"]
Browser <-->|HTTP| Server
Server -->|REST| Discogs
Server -->|Vision| Anthropic
data/ # auto-created, git-ignored
βββ collection.json # main database
βββ covers/ # locally captured cover photos
β βββ cover_42.jpg
βββ server.crt # auto-generated TLS cert
βββ server.key
Three methods for adding vinyl to the collection:
-
Photo β Take or upload a photo. The app first tries barcode detection on the still image. If no barcode is found, it sends the image to Claude Vision for cover identification. The identified artist/title is then searched on Discogs.
-
Live scan β Point the camera at a barcode. Quagga.js runs in LiveStream mode with a confidence threshold (3 consistent reads required). Once detected, automatically searches Discogs.
-
Manual search β Type artist, album, or label name. Results show cover thumbnails, year, label, and format.
After selecting a release, a confirmation screen shows full metadata, marketplace prices, and lets the user take/upload a custom cover photo and add personal notes before saving.
Three price tiers are tracked per record: Low (lowest listed), Median (VG+ suggested), and High (Near Mint suggested). Prices are fetched when a release is selected, when a detail modal is opened (if missing), and via a one-per-session background batch refresh for stale records. The batch refresh runs server-side with rate-limit delays and stops on 429 responses.
New records are automatically added to your Discogs collection (folder 1). If already present, sync is skipped.
Cover images come from Discogs by default. Users can take or upload a custom cover photo. HEIC files (from iPhone) are converted to JPEG using a fallback chain: sips (macOS) β heic2any (browser) β native decoder.
On startup the client checks /api/status and shows actionable error banners if the Discogs token is missing or invalid. Attempting to use photo mode without an Anthropic API key shows a dialog explaining how to configure it.
Camera access requires a secure context. The server auto-generates a self-signed TLS certificate for HTTPS. On mobile, open the HTTPS URL and accept the certificate warning once.
No pip packages required β uses only stdlib modules: http.server, json, ssl, urllib, threading, subprocess, base64, concurrent.futures.
External tools (optional, for HEIC conversion): sips (macOS built-in), convert (ImageMagick), ffmpeg.
Loaded from CDN, no build step:
- Bootstrap 5.3.2 (CSS + JS)
- Bootstrap Icons 1.11.3
- Quagga.js 0.12.1 (barcode scanning)
- heic2any 0.0.4 (HEIC conversion fallback)
- Discogs API β Personal access token auth. Used for search, release metadata, marketplace pricing, and collection management.
- Anthropic Claude API (optional) β Used for cover photo identification via Claude Vision.
CI runs Python checks (syntax, imports, unit tests, lint, security) and screenshot tests on every push and PR.
Screenshot tests use Playwright inside Docker to ensure pixel-perfect rendering regardless of the host OS. Tests run against both mobile (390Γ844) and desktop (1280Γ800) viewports.
# Build the test image (required once, or after dependency changes)
npm run test:screenshots:build
# Run screenshot tests
npm run test:screenshots
# Regenerate baselines after intentional UI changes
npm run test:screenshots:updateTo run from source with Docker:
# Build and run locally (uses your local code, not Docker Hub)
docker build -t eboudrant/more-wax:latest .
docker compose upNote: docker compose up alone pulls the published image from Docker Hub. To test local changes, build the image first as shown above.
The setup wizard is the recommended way to configure More'Wax. For advanced use cases (CI, scripting, Docker Compose), you can set tokens via environment variables instead β they take precedence over wizard-saved values.
# Docker: pass tokens directly
docker run -d \
-e DISCOGS_TOKEN=your-token \
-e ANTHROPIC_API_KEY=your-key \
-p 8765:8765 -p 8766:8766 \
-v morewax-data:/app/data \
eboudrant/more-wax:latest
# Local: export before running
export DISCOGS_TOKEN=your-token
python3 server.pySee .env.example for all available variables.
To access More'Wax outside your local network, put it behind a reverse proxy with a real domain. Google OAuth is available to protect access β auth is disabled by default on LAN and only activates for requests through your public domain.
Cloudflare Tunnel (easiest β no port forwarding needed):
cloudflared tunnel --url http://localhost:8765Caddy (automatic HTTPS via Let's Encrypt):
wax.yourdomain.com {
reverse_proxy localhost:8765
}
- Create a project at console.cloud.google.com
- Go to APIs & Services β OAuth consent screen β create (External)
- Go to Credentials β Create OAuth client ID (Web application)
- Add
https://yourdomain.com/auth/callbackas an authorized redirect URI - Add
https://yourdomain.comas an authorized JavaScript origin - In More'Wax, open Settings and paste the Client ID and Client Secret under Authentication
The first Google account to sign in becomes the owner β no further configuration needed. Additional emails can be added in settings.
Note: Google may take up to 5 minutes to propagate new OAuth credentials. If you get a redirect error, wait and try in an incognito window.
- Fork the repository
- Create a feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add my feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request
This project was entirely vibe-coded using Claude Code and Google Stitch.



