A Jellyseerr-like app for searching, downloading, and importing ebooks into Calibre-Web.
Bookseerr is a self-hosted app that connects Prowlarr, qBittorrent, and Calibre-Web behind a modern React UI and an Express API. It helps you search for books, download the best match, and automatically import completed files into your library.
- React frontend built with
Vite - Search view with rich result cards, covers, and quick filters
- Recent searches persisted locally for quick re-triggering
- Recent job activity with retry and re-download actions
- Full settings UI for ranking, download, and Calibre-Web behavior
- Automatic import pipeline from completed downloads into Calibre-Web
- Optional destination shelf selection and last-shelf memory
frontend/: React 19 + Vitesrc/: Express API, services, watcher, import pipelinelocales/: UI translationsDockerfile: multi-stage build for frontend + backend
Bookseerr integrates:
Prowlarrfor ebook searchqBittorrentfor download managementCalibre-Webfor library import and shelf assignment- A local watcher that detects finished downloads and starts the import flow
Typical flow:
Open UI → search book → start download/request best → watcher detects file → Calibre-Web import
The old vanilla frontend has been replaced by a React application. In production, Express serves the built app from frontend/dist. During development, Vite can run separately and proxy API requests to the backend.
Current UI features include:
- Search input with keyboard submit
- Quick filters such as EPUB-only, Spanish-only, and
< 20 MB - Recent searches shown under the search field
- One-click re-run of a recent search
- Clear recent search history
- Recent job activity with retry for failed jobs and re-download for completed ones
- Destination shelf selector when configured
- Full settings page for search and download preferences
- Result cards with cover, metadata, and direct download actions
Recent searches are stored in the browser with localStorage, so they persist across reloads on the same device.
bookseerr/
├── frontend/
│ ├── src/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── lib/
│ │ ├── App.jsx
│ │ ├── main.jsx
│ │ └── styles.css
│ └── vite.config.cjs
├── locales/
│ ├── en/
│ └── es-ES/
├── src/
│ ├── config/
│ ├── lib/
│ ├── middleware/
│ ├── repositories/
│ ├── routes/
│ ├── services/
│ ├── utils/
│ ├── app.js
│ └── server.js
├── Dockerfile
├── docker-compose.example.yml
├── package.json
└── README.md
- Node.js
>= 18 - Access to
Prowlarr - Access to
qBittorrent - Access to
Calibre-Web - A shared downloads directory visible to both Bookseerr and qBittorrent
npm installcp .env.example .envEdit .env with your URLs, credentials, folders, and optional shelf settings.
npm run devThis starts the Express server on http://localhost:3000.
In a second terminal:
npm run dev:webThis starts Vite on http://localhost:5173 and proxies /api, /locales, and /health to the backend.
npm run build
npm startIn production, Express serves the built frontend from frontend/dist.
npm run dev # Express API with nodemon
npm run dev:api # same as dev
npm run dev:web # Vite React frontend
npm run build # production frontend build
npm start # production serverPORT=3000
LOG_LEVEL=info
PROWLARR_BASE_URL=http://prowlarr:9696
PROWLARR_API_KEY=your_prowlarr_api_key
QBITTORRENT_BASE_URL=http://qbittorrent:8080
QBITTORRENT_USERNAME=admin
QBITTORRENT_PASSWORD=your_password
QBITTORRENT_CATEGORY=books
QBITTORRENT_SAVE_PATH=/downloads
CALIBRE_WEB_BASE_URL=http://calibre-web:8083
CALIBRE_WEB_USERNAME=admin
CALIBRE_WEB_PASSWORD=your_password
CALIBRE_WEB_LOGIN_PATH=/login
CALIBRE_WEB_UPLOAD_PAGE=/
FEATURE_DESTINATION_SHELF=false
DESTINATION_SHELVES=[]
DOWNLOADS_DIR=/downloads
LIBRARY_DIR=/library
STATE_FILE=/data/state.json
WATCHER_ENABLED=true
WATCH_EXTENSIONS=.epub,.mobi,.azw3
WATCH_DEBOUNCE_MS=8000
POST_IMPORT_ACTION=move
PROCESSED_DIR=/downloads/.imported
REQUEST_TIMEOUT_MS=30000Example DESTINATION_SHELVES value:
FEATURE_DESTINATION_SHELF=true
DESTINATION_SHELVES=[{"id":"maria","label":"Maria","qbSavePath":"/downloads/maria","calibreShelf":"Maria","calibreShelfId":1},{"id":"infantil","label":"Infantil","qbSavePath":"/downloads/infantil","calibreShelf":"Infantil","calibreShelfId":2}]When destination shelves are enabled, the frontend shows an Estantería de destino selector and the chosen option is used to:
- keep the qBittorrent category unchanged
- optionally save the book into a destination-specific download folder
- preserve that destination in job tracking
- use a fixed
calibreShelfIdwhen available for deterministic shelf assignment - upload the book to Calibre-Web and assign the configured shelf afterwards
Notes:
calibreShelfIdis the most reliable option if you already know the shelf IDs in Calibre-Web.qbSavePathmay differ fromDOWNLOADS_DIRas long as both point to the same mounted folder from the perspective of qBittorrent and Bookseerr.- If you use custom
qbSavePathvalues such as/downloads/maria, create those folders in advance and make sure they are writable.
To allow Bookseerr to communicate correctly with the qBittorrent WebUI API, disable these options in:
qBittorrent → Settings → Web UI → Security
- Disable CSRF protection
- Disable Host header validation
If these stay enabled, requests may fail with 403 Forbidden or authentication may fail silently when running behind Docker or reverse proxies.
Returns service status.
Searches ebooks using Prowlarr and the currently active search settings.
curl "http://localhost:3000/api/search?query=dune"Starts a manual download.
curl -X POST "http://localhost:3000/api/download" \
-H "Content-Type: application/json" \
-d '{
"title": "Dune",
"downloadUrl": "magnet:?xt=urn:btih:...",
"protocol": "torrent"
}'Searches and starts the best available result automatically.
curl -X POST "http://localhost:3000/api/request" \
-H "Content-Type: application/json" \
-d '{
"query": "Dune"
}'Returns frontend settings, feature flags, destination shelves, and available indexers.
Persists frontend-managed settings.
Returns tracked jobs.
Creates a new download job using the stored data from a failed or completed tracked job.
- The user searches for a book or requests the best match.
- Prowlarr returns ranked results using the active filters and preferences.
- qBittorrent starts the selected download.
- The watcher detects completed files in the downloads folder.
- The import service uploads the book to Calibre-Web.
- The file is moved or deleted based on
POST_IMPORT_ACTION.
docker build -t bookseerr .docker run -d \
-p 3000:3000 \
--env-file .env \
-v /your/downloads:/downloads \
-v /your/library:/library \
-v /your/data:/data \
--name bookseerr \
bookseerrA docker-compose.example.yml is included.
Typical steps:
- Copy it to
docker-compose.yml - Update the build path if needed
- Adjust volumes and
.env - Run
docker compose up -d --build
/downloadsmust match the path visible to qBittorrent/librarymust match the Calibre-Web library path/datashould be persisted to keep state and settings- Check filesystem permissions carefully, especially on NAS setups
- Automatic destination shelves
- React frontend migration
- Configurable settings UI
- Recent searches and quick re-run
- Favorites / watchlist system
- Enhanced job tracking and activity view
- Notifications for download and import status
- Better Calibre-Web workflows and shelf tooling
- Optional discovery and metadata features
MIT License © 2026 Cruzadera

