Self-hosted · single-user · archive-first
Every log. One archive.
Aggregato pulls your films, series, books, anime and listens out of the platforms you already log them on, and keeps them in one local database you own.
- Letterboxd films
- ListenBrainz listens
- AniList anime
- Goodreads books
- Koito listens
- Spotify listens
Outbound requests on a fresh install
Nothing leaves until you say so.
A new install talks to no one. Nothing is fetched until you enable a platform yourself, and Aggregato never enriches your data from third-party metadata sources: what you see is what your platforms said, unified and handed back to you.
What it does
Your history, kept honest.
-
One log across every platform
A film you rated on Letterboxd and an album you scrobbled sit in the same timeline, the same search and the same statistics. Search covers titles and your own reviews.
-
Ratings stay what you gave
4 of 5 stars and 8 of 10 are stored as each platform said them, with their scale — not flattened into one invented number.
-
No fabricated precision
An entry logged as “May 2019” stays a month, not a guessed day.
-
Archive-first
Retained raw payloads let normalization fixes be replayed without contacting a platform. Entries are stored locally; a provider change or outage does not remove data already collected.
-
Local storage
SQLite is the default database and lives in the data directory or Compose volume you configure. Settings can download an archive for an on-disk SQLite database; PostgreSQL deployments use PostgreSQL backup tools.
A tour
Six screens, one archive.
Screenshots from a demo archive of about two thousand entries across five platforms. Select any of them to see it full size.
-
01 · DASHBOARD
Is everything working?
The newest entries, and whether every provider is actually syncing. A provider in trouble is named, not reduced to a badge.
- Live sync activity
- Per-provider health
-
02 · LOG
Everything you logged, in order.
Filter by media family, type, platform, kind of entry or date range. Films, anime episodes and books interleave in one timeline.
- Full-text search over titles and reviews
- Stable, cursor-based paging
-
03 · STATISTICS
A year at a glance.
An activity heatmap of every entry, plus your most logged works and creators — counted by what you logged, not by normalized scores.
- Per-year activity
- Top works and creators
-
04 · WORK
Every opinion, on its own scale.
A work shows each platform's rating as given, its 0–100 value within that scale only, your review, the credits in the platform's own words, and every identifier it came with.
- Merge and split duplicates
- Identity links you can audit
-
05 · PROVIDERS
Configure, check, sync.
Each platform's form is generated from what it actually needs. Secrets are never shown again, and settings pinned by your config file say so.
- Check credentials without syncing
- Sync now or full resync
-
06 · SYNC HISTORY
What ran, and what went wrong.
Every attempt a provider made, grouped by the run it retried, with counts and the class of any error — so a broken platform looks broken instead of looking empty.
- Retries grouped by lineage
- Ingest failures kept with their payloads
Bundled platforms
Where it reads from.
Provider operations run in short-lived child processes without a database engine, with a timeout. This limits the effect of ordinary crashes and hangs; provider code is not sandboxed, so review drop-ins before enabling them.
- KoitoListensServer URL and API keyevery 5 min
- ListenBrainzListens — or any compatible server, such as MalojaUsername and user tokenevery 15 min
- AniListAnime and manga, with ratingsUsername, plus an OAuth token for private listshourly
- LetterboxdFilms and series, with ratings and reviewsUsername or public RSS URLevery 6 h
- GoodreadsBooks, with ratings and reviews from its rolling feedPublic profile or RSS URLdaily
- SpotifyRecently played tracksApp client ID and secret, plus a refresh tokenevery 15 min
Anything else is a plugin away — see writing a provider. No CAPTCHA or anti-bot circumvention, ever: a blocked platform is marked degraded and left alone.
Set it up
Running in three commands.
One named volume. No database server or message broker is needed for the default SQLite setup. Images are published for amd64 and arm64.
- Docker
- ≈ 5 minutes
-
Start it
Clone the repository, generate a token and bring the stack up. Keep the token — it is your login.
$ git clone https://github.com/minipps/aggregato && cd aggregato $ export AGGREGATO_TOKEN=$(openssl rand -hex 32) # keep this $ docker compose -f docker/compose.yml up -dSet
AGGREGATO_FRONTEND_PORTif port 8000 is already taken, andAGGREGATO_VERSIONto pin a release. -
Sign in
Open localhost:8000 and paste the token. The frontend container serves the app and proxies
/apito the backend, which runs both the API and the scheduler. -
Connect a platform
On the Providers screen:
- Pick a platform, press Configure provider, fill in the form and Save configuration.
- Press Check provider to test the saved credentials.
- Press Enable, then Sync now for the first pass.
- The scheduler polls at the platform's own interval from here on.
Your log fills in as syncs land: Log is the timeline, Statistics the summaries, Sync history what ran, and Settings holds retention and storage details.
-
Or keep it all in a file
Provider settings can also live in YAML. Point
AGGREGATO_CONFIGat it;${VAR}references resolve at read time and are never written back or returned by the API.providers: listenbrainz: username: your-name token: ${LISTENBRAINZ_TOKEN} letterboxd: username: your-name goodreads: profile_url: https://www.goodreads.com/user/show/your-idA broken block disables that one platform, never the rest. Want to let others browse? Set
AGGREGATO_READONLY_TOKEN— the server refuses its writes, not just the buttons.
With SQLite, the database and local files live in /data on the aggregato-data volume and survive restarts and upgrades. docker compose down --volumes deletes the volume. PostgreSQL stores the database separately; use PostgreSQL backup tools and preserve the image cache. See the operations guide.