A free public instance of Libex is available at Libex
This instance is maintained by the Libex project and is free for community use. No API key required. No rate limits beyond what Audible naturally enforces.
If you rely on Libex for a project or tool, we recommend self-hosting your own instance for reliability and control.
The audiobook automation community has long depended on metadata services to power tools like Readarr, Audiobookshelf, and custom managers. When those services disappear or restrict usage, every project depending on them breaks.
Libex exists to be a permanent, community-owned alternative:
- MIT licensed — no restrictions, fork it, build on it, use it however you want
- No usage restrictions — works with any software, any workflow
- Drop-in replacement — compatible with AudiMeta's API endpoints
- Audible-first — always fetches fresh data, the local database is a fallback not a crutch
- Persistent local library — every book, author, and series ever requested is stored and queryable
- All regions — full support for all Audible markets without language restrictions
- Self-hostable — one
docker compose upand you're running
Pull the image:
# GHCR
docker pull ghcr.io/libexhq/libex:latest
# Docker Hub
docker pull sunbrolynk/libex:latestDeploy:
# 1. Create a directory
mkdir libex && cd libex
# 2. Download the compose file
curl -O https://raw.githubusercontent.com/LibexHQ/Libex/main/docker-compose.yml
# 3. Create your environment file
cp .env.example .env
# Edit .env — DB_PASSWORD is required, all other values have sensible defaults
# 4. Start Libex
docker compose up -d
# 5. Verify
curl http://localhost:3333/healthOr copy the compose file directly:
services:
libex:
image: ghcr.io/libexhq/libex:latest
container_name: libex
restart: unless-stopped
ports:
- "${PORT:-3333}:3333"
environment:
- DATABASE_URL=postgresql+asyncpg://${DB_USER:-libex}:${DB_PASSWORD}@postgres:5432/${DB_NAME:-libex}
- CACHE_ENABLED=${CACHE_ENABLED:-true}
- CACHE_TTL=${CACHE_TTL:-86400}
- DEFAULT_REGION=${DEFAULT_REGION:-us}
- PORT=${PORT:-3333}
- LOG_RETENTION_DAYS=${LOG_RETENTION_DAYS:-7}
- AXIOM_TOKEN=${AXIOM_TOKEN}
- AXIOM_DATASET=${AXIOM_DATASET:-libex}
- SEEDER_ENABLED=${SEEDER_ENABLED:-false}
- SEEDER_INTERVAL_HOURS=${SEEDER_INTERVAL_HOURS:-24}
- SEEDER_REQUEST_DELAY=${SEEDER_REQUEST_DELAY:-1.0}
- SEEDER_REGIONS=${SEEDER_REGIONS:-us}
- AUDIBLE_PROXY_URL=${AUDIBLE_PROXY_URL}
volumes:
- ./logs:/app/logs
depends_on:
postgres:
condition: service_healthy
networks:
- default
- libex-proxy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3333/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
postgres:
image: postgres:16-alpine
container_name: libex-postgres
restart: unless-stopped
ports:
- "5432:5432"
environment:
POSTGRES_DB: ${DB_NAME:-libex}
POSTGRES_USER: ${DB_USER:-libex}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- ./data/postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-libex}"]
interval: 10s
timeout: 5s
retries: 5
networks:
libex-proxy:
name: libex-proxy
driver: bridgeThe public instance uses Axiom for structured request logging. This is disclosed transparently.
What is logged:
- Request path and parameters (e.g. which ASIN was requested, which region)
- Response time and status code
- IP address
- User agent
- Cache hit/miss
- Errors and exceptions
What is NOT logged:
- Any personally identifiable information beyond the above
Why we log: Logging helps us understand how Libex is being used, identify broken endpoints, debug errors, and improve the service. Without visibility into what's failing, we can't fix it.
Who can see the logs: Only the instance maintainer has access to the Axiom dataset. Logs are retained for 30 days and then automatically deleted by Axiom. No logs are shared with third parties.
If you self-host:
Logging is completely optional. Leave AXIOM_TOKEN empty and Libex logs to stdout only. Nothing leaves your server.
HTML content: description and summary fields on book responses, description on author responses, and description on series responses are returned as plain text with HTML stripped.
Image URLs: Cover image URLs are returned with Audible size suffixes stripped, giving you the base high-resolution image URL.
ASIN validation: All ASIN parameters are validated against Audible's 10-character alphanumeric format. Invalid ASINs return a 404 with a clear error message.
Region validation: All region parameters are validated against supported Audible regions. Invalid regions return a 400 error.
Local database: Every successful Audible response is written to a persistent relational database. This powers the DB query endpoints and serves as a fallback when Audible is unavailable.
Virtual Voice Audiobooks: Book responses include isVvab (boolean indicating whether the book is a Virtual Voice Audiobook — AI-narrated rather than human-narrated).
Audible plans: Book responses include plans (list of Audible plan names such as "US Minerva" or "AccessViaMusic"), letting clients determine subscription availability programmatically.
Narrator profiles: Narrator responses from /db/narrator include enrichment data sourced from NarratorList.com and AussieNarrator.com where available. When profile data is present, the response includes source, sourceUrl (link to the narrator's full profile), sourceUpdatedAt, and an attribution string (e.g. "Profile data provided by NarratorList.com, retrieved May 2026"). Consumers displaying narrator data should include this attribution where practical.
Audiobookshelf's custom metadata provider calls /{region}/search, not /search. When configuring ABS, set your base URL to include the region:
http://YOUR-IP:3333/us
ABS will then call /us/search?title=...&author=... which returns the {"matches": [...]} format ABS expects. The flat /search endpoint returns a different format that ABS cannot parse.
| Method | Endpoint | Description |
|---|---|---|
| GET | /book/{asin} |
Get book by ASIN |
| GET | /book |
Get multiple books by ASIN (comma-separated, max 1000) |
| GET | /book/{asin}/chapters |
Get chapter information |
| GET | /book/sku/{sku} |
Get all region variants of a book by SKU group |
| GET | /author/{asin} |
Get author profile |
| GET | /author/{asin}/books |
Get all books by author ASIN |
| GET | /author/books/{asin} |
Get all books by author ASIN (legacy) |
| GET | /author/books |
Get books by author name |
| GET | /author |
Search authors by name |
| GET | /series/{asin} |
Get series metadata |
| GET | /series/{asin}/books |
Get all books in a series |
| GET | /series/books/{asin} |
Get all books in a series (legacy) |
| GET | /series |
Search series by name |
| GET | /narrator/books |
Get books by narrator name |
| GET | /search |
Search Audible catalog |
| GET | /quick-search |
Quick search via suggestions |
| GET | /{region}/search |
Regional search for Audiobookshelf compatibility |
| GET | /{region}/quick-search/search |
Regional quick search for Audiobookshelf compatibility |
| GET | /db/book |
Query the local indexed book library |
| GET | /db/book/{asin} |
Get a single book from local DB |
| GET | /db/book/{asin}/chapters |
Get chapter data from local DB |
| GET | /db/book/sku/{sku} |
Get books by SKU group from local DB |
| GET | /db/plans |
Get all distinct Audible plan names from local DB |
| GET | /db/plans/{plan_name} |
Get all books under a specific plan from local DB |
| GET | /db/vvab |
Get all virtual voice audiobooks (AI-narrated) from local DB |
| GET | /db/stats |
Get counts of books, authors, narrators, and series in local DB |
| GET | /db/author/{asin} |
Get author from local DB |
| GET | /db/author/{asin}/books |
Get author's books from local DB |
| GET | /db/narrator |
Search narrators by name from local DB |
| GET | /db/narrator/books |
Get books by narrator name from local DB |
| GET | /db/series/{asin} |
Get series from local DB |
| GET | /db/series/{asin}/books |
Get series books from local DB |
| GET | /health |
Health check |
Full interactive documentation available at /docs when running.
GET /db/book queries books that have been fetched and stored locally without hitting Audible. Useful for searching your indexed library by metadata.
All parameters are optional but at least one filter must be provided. Supports pagination via limit (default 20, max 100) and page (default 1).
| Parameter | Type | Match |
|---|---|---|
title |
string | ILIKE |
subtitle |
string | ILIKE |
author_name |
string | ILIKE (join) |
series_name |
string | ILIKE (join) |
description |
string | ILIKE |
summary |
string | ILIKE |
publisher |
string | ILIKE |
copyright |
string | ILIKE |
isbn |
string | ILIKE |
region |
string | exact |
language |
string | exact |
book_format |
string | exact |
content_type |
string | exact |
content_delivery_type |
string | exact |
rating_better_than |
float | >= |
rating_worse_than |
float | <= |
longer_than |
int | >= (minutes) |
shorter_than |
int | <= (minutes) |
explicit |
bool | exact |
whisper_sync |
bool | exact |
has_pdf |
bool | exact |
is_listenable |
bool | exact |
is_buyable |
bool | exact |
is_vvab |
bool | exact |
plan_name |
string | JSONB contains |
| Code | Region |
|---|---|
us |
United States |
uk |
United Kingdom |
ca |
Canada |
au |
Australia |
de |
Germany |
fr |
France |
it |
Italy |
es |
Spain |
jp |
Japan |
in |
India |
br |
Brazil |
Copy .env.example to .env and configure:
| Variable | Default | Description |
|---|---|---|
DB_PASSWORD |
— | Required. PostgreSQL password |
DB_NAME |
libex |
PostgreSQL database name |
DB_USER |
libex |
PostgreSQL username |
PORT |
3333 |
Host port the API is exposed on |
DEFAULT_REGION |
us |
Default Audible region |
CACHE_ENABLED |
true |
Enable or disable the cache |
CACHE_TTL |
86400 |
Cache TTL in seconds (default 24 hours) |
LOG_RETENTION_DAYS |
7 |
Days of rotated logs to keep. 0 = infinite, no rotation |
AXIOM_TOKEN |
— | Axiom API token (optional — leave blank for stdout only) |
AXIOM_DATASET |
libex |
Axiom dataset name |
SEEDER_ENABLED |
false |
Enable background DB seeder |
SEEDER_INTERVAL_HOURS |
24 |
Hours between seeder cycles |
SEEDER_REQUEST_DELAY |
1.0 |
Seconds between Audible requests during seeding |
SEEDER_REGIONS |
us |
Comma-separated regions to seed (e.g. us,uk,de) |
AUDIBLE_PROXY_URL |
— | Proxy URL for outbound Audible requests only. Supports http://, https://, socks5://. API serving is unaffected |
SEED_SECRET |
— | PBKDF2 hash for the internal seed endpoint. Empty = endpoint disabled. Generate with python -m app.api.routes.internal.router |
DATABASE_URL is constructed automatically by docker-compose from DB_NAME, DB_USER, and DB_PASSWORD. Only set it manually if running outside of Docker.
Libex is API-compatible with AudiMeta. To migrate:
- Deploy Libex using the quick start above
- Update your base URL from your AudiMeta instance to your Libex instance
- That's it — no other changes required
- Libex uses PostgreSQL as both a persistent library and a cache — no Redis required
- Every book, author, series, narrator, and genre ever requested is stored in a full relational schema and survives cache expiry indefinitely
- The local library powers the
/db/bookand/book/sku/{sku}endpoints and serves as an automatic fallback when Audible is unavailable - Cache entries expire after
CACHE_TTLseconds (default 24 hours); expired entries are purged automatically - Logs directory:
./logs(relative to your compose file) — Libex writes a rotating log file to./logs/libex.logon the host - Log rotation is daily.
LOG_RETENTION_DAYS=7keeps 7 days of backups. Set to0for infinite retention with no rotation - Database seeder: Set
SEEDER_ENABLED=trueto activate the background seeder. It expands the local DB by walking author relationships (discovers books you haven't requested yet) and scanning for new Audible releases. Each cycle compounds — a single book fetch can seed hundreds of related books over time. The seeder runs everySEEDER_INTERVAL_HOURS(default 24) and rate-limits itself to one Audible request perSEEDER_REQUEST_DELAYseconds (default 1.0). ConfigureSEEDER_REGIONSto seed multiple markets (e.g.us,uk,de) - VPN proxy: Set
AUDIBLE_PROXY_URLto route outbound Audible API requests through a proxy. Only Audible requests are affected — API serving, database connections, and logging are completely unaffected. This is especially useful when running the seeder to avoid IP-based rate limiting. Any HTTP, HTTPS, or SOCKS5 proxy works. The compose file creates alibex-proxyDocker network automatically — connect your VPN proxy container to it, then setAUDIBLE_PROXY_URLto point at the proxy. LeaveAUDIBLE_PROXY_URLblank to disable
Contributions are welcome. See CONTRIBUTING.md for branch naming, commit conventions, and PR requirements.
Libex is a metadata tool that fetches publicly available information from Audible's API. It does not host, distribute, or provide access to copyrighted audio content. Users are responsible for ensuring their use complies with applicable laws and Audible's terms of service.
Audible — All metadata is sourced from Audible's public API. Libex is an independent project and is not affiliated with, endorsed by, or sponsored by Audible or Amazon.
NarratorList.com — Narrator profile data including biographies, images, languages, and accent ratings is sourced from NarratorList.com. NarratorList is a community-built database where audiobook narrators curate their own profiles. Maintained by Amy Soakes.
AussieNarrator.com — Additional narrator profile data for Australian and New Zealand narrators. A sister site to NarratorList.com, also maintained by Amy Soakes.
Axiom — Structured logging for the public instance. Axiom provides the observability layer that helps us monitor and improve Libex.
AudiMeta — The original Audible metadata service that inspired Libex and demonstrated the community need for this tooling. Credit to Vito0912 for pioneering this space.
FastAPI — The modern Python web framework powering Libex.
SQLAlchemy — Async database toolkit for Python powering Libex's full relational schema across books, authors, series, narrators, genres, and their relationships.
MIT — see LICENSE for details.