Velvarr is a free and open source discovery and request app for adult media. Browse movies, scenes, performers, and studios from TPDB and StashDB, request them into Whisparr (Eros) with administrator approval, and watch in Jellyfin through a credential-free link.
Docker is the recommended way to run Velvarr. It uses compose.yaml and the image ghcr.io/skare69/velvarr.
- Get the compose file.
- Create
.env.localwith the operator secrets. Without it, you cannot create the owner account. - Start the container and open http://127.0.0.1:6699.
Linux and macOS:
mkdir velvarr && cd velvarr
curl -fsSLO https://raw.githubusercontent.com/Skare69/velvarr/main/compose.yaml
printf 'VELVARR_SECRET_KEY=%s\nVELVARR_SETUP_SECRET=%s\n' \
"$(openssl rand -hex 32)" "$(openssl rand -base64 32 | tr '+/' '-_' | tr -d '=')" > .env.local
docker compose up -dWindows (PowerShell):
mkdir velvarr; cd velvarr
Invoke-WebRequest https://raw.githubusercontent.com/Skare69/velvarr/main/compose.yaml -OutFile compose.yaml -UseBasicParsing
$rng = [Security.Cryptography.RandomNumberGenerator]::Create()
$k = [byte[]]::new(32); $s = [byte[]]::new(32); $rng.GetBytes($k); $rng.GetBytes($s)
$key = -join ($k | ForEach-Object { $_.ToString('x2') })
$setup = [Convert]::ToBase64String($s).TrimEnd('=').Replace('+', '-').Replace('/', '_')
Set-Content .env.local "VELVARR_SECRET_KEY=$key`nVELVARR_SETUP_SECRET=$setup" -Encoding ascii
docker compose up -dImportant
Back up VELVARR_SECRET_KEY. If you lose it, you cannot read the database or any backup.
On the first visit, enter VELVARR_SETUP_SECRET as the setup secret to create the owner account.
Upgrade: set the new image tag in compose.yaml, then run docker compose pull && docker compose up -d.
Health: the container health check reads /api/status. If the container is unhealthy, /api/status failed: Velvarr cannot open /data, or the database file is not a Velvarr database or was written by a newer version. Run docker compose logs velvarr to see the cause.
Requires Node 24.21+ and Bun 1.3.14+. The commands are the same on Linux, macOS, and Windows.
git clone https://github.com/Skare69/velvarr.git && cd velvarr
bun install
bun run setup # writes .env.local with fresh secrets; never overwrites it
bun run dev # http://127.0.0.1:6699Checks before a commit:
bun run format && bun run check && bun run test && bun run builddocs/how-it-works.md explains how the code is
put together: the architecture map, the request-to-playback flow, and
the acquisition life cycle, each tied to its source paths.
- Catalogs: movies (TPDB), scenes (TPDB and StashDB), performers, and studios, with the filters and sort orders that each provider supports.
- Browse: one grid for TPDB movies and StashDB scenes, with search, tag include and exclude, studio, performer, and date filters. The URL holds every filter.
- Search, Studios, and Genres across both providers. Velvarr never merges results across providers. Cross-provider identity comes only from links that the providers publish.
- Requests with administrator or moderator approval, and an optional auto-approve grant for each account.
- Crash-safe acquisition into Whisparr: Velvarr records each attempt before the network call, so a restart never loses or duplicates an add.
- Jellyfin availability for each user, and watch links without credentials.
- Performer follows across both providers, with a Following view and a Discover rail.
- Preferences: hidden tags and Discover shelf order for each account.
- Similar titles for movies and scenes, and Often appears with for performers.
- Update notice when a newer GitHub release is available.
- Optional: Discord notifications, and AI-assisted title matching through TypeSafe or a local Ollama decision model. AI only flags a near match for administrator review. It never marks a title as available.
Put the variables in .env.local.
| Variable | Required | Meaning |
|---|---|---|
VELVARR_SECRET_KEY |
yes | 64 hex characters. Decrypts the credentials in the database. A restore needs the key from the time of the backup. |
VELVARR_SETUP_SECRET |
until bootstrap | 32 characters or more. Gates the one-time owner setup. |
VELVARR_ORIGIN |
no | The public origin, for example behind a reverse proxy. Velvarr refuses changes from other origins. An https: origin marks the session cookie Secure. |
VELVARR_DATA_DIR |
no | Data directory. Default ./data, and /data in the container. |
VELVARR_ALLOW_HTTP |
no | 1 allows plain HTTP to private and Docker-network addresses. |
VELVARR_DISCORD_WEBHOOK_URL |
no | Private Discord webhook (https only). |
VELVARR_DISCORD_DETAIL |
no | 1 adds titles to notifications. By default, messages contain only identities. |
TPDB_API_TOKEN |
no | TPDB token for calls made without a token saved in Settings. A saved token wins. |
STASHDB_API_KEY |
no | StashDB key for calls made without a key saved in Settings. A saved key wins. |
TPDB_BASE_URL |
no | TPDB API root override. Default https://api.theporndb.net. |
STASHDB_BASE_URL |
no | StashDB API root override. Default https://stashdb.org. |
TYPESAFE_BASE_URL |
no | TypeSafe cloud API root override. Unset uses the TypeSafe default. |
TYPESAFE_DEFAULT_MODEL |
no | TypeSafe decision model override. Unset uses the TypeSafe default. |
TYPESAFE_API_KEY |
no | TypeSafe key for AI-assisted matching. A key saved in Settings wins. Tag suggestions need a key saved in Settings. |
VELVARR_JUDGMENT_PROVIDER |
no | typesafe (default) or ollama. A choice saved in Settings wins. Tag suggestions need a choice saved in Settings. |
OLLAMA_BASE_URL |
no | Ollama API root. Default http://localhost:11434. |
OLLAMA_MODEL |
no | Ollama decision model. Default nimble. |
VELVARR_UPDATE_CHECK |
no | 0 disables the release check. Otherwise, the server asks api.github.com at most once an hour after a success and at most once every ten minutes after a failure. |
Unless VELVARR_ORIGIN is https:, the cookie is Secure only when the proxy sends X-Forwarded-Proto: https or the request URL is https. On each change request, a supplied Sec-Fetch-Site header must say same-origin, and a request that sends a body or a Content-Type header must send application/json.
Each failed sign-in writes one log line: [auth] failed sign-in attempt: account="<name>" ip="<address>". The log never contains the password. The address is the first X-Forwarded-For entry, or unknown. A client can set this header. Trust the address only when your proxy replaces the header.
Velvarr is an installable app, but the install prompt needs HTTPS. Tailscale gives you HTTPS with little work:
- In the Tailscale admin console, enable MagicDNS and HTTPS certificates.
- On the Velvarr machine, run
tailscale serve --bg 6699. - On the phone, open
https://<machine>.<tailnet>.ts.netand select Add to home screen.
- If
VELVARR_ORIGINholds a different address, phone sign-in fails withorigin_mismatch. Set it to the ts.net address or remove it. Only one origin can be set. - The service worker caches only build assets, never
/apior live data. It registers only on HTTPS or loopback, and never in development builds.
Use Ollama 0.35 or later with a decision model such as nimble or tev1. Chat models do not support the /v1/systemone endpoint.
ollama pull nimble- Open Settings → Metadata providers → AI-assisted matching and select Ollama (local).
- Enter the Ollama URL and the model name from
ollama list, then save. - Select Test saved connection.
Ollama URL:
- Velvarr runs natively on the same machine:
http://localhost:11434. - Velvarr runs in Docker Desktop:
http://host.docker.internal:11434, and setVELVARR_ALLOW_HTTP=1. - Ollama runs on a different host: use its private address. See the Ollama network guide.
Ollama never falls back to the paid TypeSafe service. If the connection fails, matching stays exact. You can also use the VELVARR_JUDGMENT_PROVIDER, OLLAMA_BASE_URL, and OLLAMA_MODEL variables. Test some real title variants before you select a model.
bun run backup /backups/velvarr.sqlite # consistent online snapshot; refuses to overwriteTo restore, copy the snapshot as velvarr.sqlite into a new, empty data directory. Start Velvarr with the same VELVARR_SECRET_KEY as at backup time. The backup does not contain the key.
| Branch / remote | Contents |
|---|---|
main |
The standalone product, without Seerr application code |
legacy/seerr-whisparr |
Seerr integration snapshot, for reference only |
upstream |
seerr-team/seerr, not a merge source |
Licensed under the MIT License.

