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
Aggregato's Statistics screen: 1,950 logged entries, a year-long activity heatmap, and the most logged works and creators.
filmPast Lives★★★★★ · Letterboxd
trackWeird Fishes/ArpeggiRadiohead · ListenBrainz
bookPiranesi5 of 5 · Goodreads
animeFrieren9.5 of 10 · AniList
trackDreamsFleetwood Mac · Koito
filmPerfect Days★★★★½ · Letterboxd
bookStonerread · May 2019 · Goodreads
trackNobodyMitski · Spotify
animeMushishiepisode 12 · AniList
filmStalker★★★★★ · Letterboxd
trackAlrightKendrick Lamar · ListenBrainz
bookThe Dispossessed5 of 5 · Goodreads
trackLazuliBeach House · Koito
filmFallen Leaves★★★★ · Letterboxd
animeDungeon Meshifinished · AniList
trackRoygbivBoards of Canada · Spotify

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.

  1. 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.

  2. 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.

  3. No fabricated precision

    An entry logged as “May 2019” stays a month, not a guessed day.

  4. 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.

  5. 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.

  1. 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
    Dashboard: a sync health card reading “Every provider is healthy” with 5 providers and 0 needing attention, above a list of recent listens.
  2. 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
    Log screen filtered to the screen family: Perfect Days and Past Lives watched on Letterboxd, then episode progress for Frieren from AniList.
  3. 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
    Statistics screen with a calendar heatmap of 1,568 entries across 271 active days in 2026 and lists of most logged works and creators.
  4. 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
    Work page for Past Lives (2023): a Letterboxd rating of 5 on the letterboxd-5-star-halves scale, normalized 100 of 100 within that scale only, liked, with Celine Song credited as director.
  5. 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
    Providers screen: 6 installed, 5 enabled. AniList is idle, with its last success, next run, capabilities, current settings and buttons to disable, check, sync now or run a full resync.
  6. 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
    Sync history for Letterboxd: a series of successful runs and one failed run with the error “transport: Connection reset by peer”.

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
  1. Start it

    Clone the repository, generate a token and bring the stack up. Keep the token — it is your login.

    shell
    $ 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 -d

    Set AGGREGATO_FRONTEND_PORT if port 8000 is already taken, and AGGREGATO_VERSION to pin a release.

  2. Sign in

    Open localhost:8000 and paste the token. The frontend container serves the app and proxies /api to the backend, which runs both the API and the scheduler.

  3. Connect a platform

    On the Providers screen:

    1. Pick a platform, press Configure provider, fill in the form and Save configuration.
    2. Press Check provider to test the saved credentials.
    3. Press Enable, then Sync now for the first pass.
    4. 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.

  4. Or keep it all in a file

    Provider settings can also live in YAML. Point AGGREGATO_CONFIG at it; ${VAR} references resolve at read time and are never written back or returned by the API.

    aggregato.yml
    providers:
      listenbrainz:
        username: your-name
        token: ${LISTENBRAINZ_TOKEN}
      letterboxd:
        username: your-name
      goodreads:
        profile_url: https://www.goodreads.com/user/show/your-id

    A 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.