Self-hosted service
FoxxMD/multi-scrobbler avatar
FoxxMD/multi-scrobbler

multi-scrobbler: One Scrobble Pipeline for Sources the Last.fm Apps Cannot See

Scrobble plays from multiple sources to multiple clients

1,263 stars60 forksTypeScriptMIT

At a glance

What is it?
FoxxMD/multi-scrobbler is a self-hosted TypeScript service that polls music sources (Plex, Jellyfin, Spotify, MPD, Subsonic and more) and forwards plays to scrobble clients such as Last.fm, ListenBrainz and Maloja. Its value is breadth and de-duplication; its cost is that every source is a separate integration you configure and keep authorised.
Who is it for?
Adopt multi-scrobbler if you play music through self-hosted servers (Plex, Jellyfin, Navidrome, MPD) or several streaming services and want one self-hosted record instead of per-app scrobbler plugins. Do not adopt it if you only listen in one app that already scrobbles natively, or if you are unwilling to run a long-lived container and re-authorise OAuth credentials when they expire.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 10, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap multi-scrobbler fills: plays that never reach a scrobbler

Scrobbling usually depends on the player. A browser extension covers web players, a mobile app covers the phone, a plugin covers the desktop client. That works until you listen somewhere the plugin does not exist. A Plex or Jellyfin server playing to a TV, a headless MPD box, a Chromecast session, a Sonos speaker, or a streaming service used through its own app on a device you do not control. In each case the play happens and nothing is recorded. multi-scrobbler moves the recording step out of the player and into a long-running service that talks to the source's API instead. The README frames the benefit as platform independence: because the app communicates directly with service APIs, it captures what you play regardless of where you play it. The second audience is people who manage listening for others. The README states the app supports configuring for single or multiple users, scrobbling for friends and family, and that sources can be siloed to specific clients to keep plays separate. That is a genuine difference from a per-device scrobbler, which is bound to one account on one machine.

Sources, Clients and the config that binds them

The model is two lists joined by configuration. A Source is a place plays come from. A Client is a place plays go to. The README lists roughly thirty sources, including Plex, Jellyfin, Kodi, MPD, Mopidy, MPRIS, Sonos, Spotify, Deezer, YouTube Music, Apple Music, Google Cast, VLC, Subsonic-compatible APIs such as Navidrome and Gonic, Music Assistant, and even Last.fm and ListenBrainz themselves as sources. Clients are a shorter list: Last.fm, Libre.fm, ListenBrainz, Maloja, Koito, Rocksky, teal.fm, plus Discord for Now Playing rather than scrobbling. Several services appear on both sides. That is deliberate. The README answers the obvious question directly: if you already scrobble to Last.fm, you can use Last.fm as a Source and forward those scrobbles to any other Client, keeping your existing setup and still capturing the data to a self-hosted location. The docs site separates these into per-source and per-client pages, and the README links a Last.fm (Endpoint) and ListenBrainz (Endpoint) variant alongside the profile-based ones, which suggests the endpoint form accepts scrobbles pushed to it rather than polling an account. That distinction matters when you pick a source, and the docs page is the place to confirm which variant fits your setup. Configuration is accepted as environment variables or JSON, and the docs describe a transforms layer for modifying data before scrobbling using regular expressions or search patterns. Transforms are the mechanism you would reach for when a source reports a title in a form the client rejects, or when the same play arrives from two sources and you need to suppress one.

Getting it running: Docker, ENVs or JSON, and one authorised client at a time

The README points to Docker images for x86 and ARM as the primary install path, with a local NodeJS install as the alternative, and links a quick start guide on the docs site. The configuration page is referenced for both env and JSON configuration types, and the README notes credentials are handled as persistent, with authorisation performed through the app. In practice that means the first run is interactive in a way a pure config file is not: you supply client credentials, the service walks you through an authorisation flow, and the resulting token is stored so later restarts do not repeat it. The exact environment variable names and JSON keys are not reproduced in the README, so the docs site is the only reliable source for them. What the README does name are the operational endpoints you would wire into existing monitoring: webhooks for Gotify, Ntfy and Apprise, healthcheck endpoints, and Prometheus metrics. It also mentions a web server interface for stats, basic control, and detailed logs, and shows a status UI screenshot. Those three surfaces (webhooks, health endpoints, Prometheus) are the ones to configure before you trust the service unattended, because a source that has silently stopped authenticating looks identical to a source with nothing playing until you check.

Where it breaks: silent sources, duplicate plays and the wrong-tool case

The failure modes follow from the architecture. Because the service polls or subscribes to remote APIs, a source can stop producing plays without the service crashing. An expired OAuth token, a changed API, or a server that moved address leaves a source configured and idle. The README's answer is monitoring rather than prevention: webhooks, healthcheck endpoints and Prometheus metrics exist precisely so you can detect that state. The second failure mode is duplication. If you listen to Spotify through a desktop client that also scrobbles to Last.fm, and you configure Spotify as a Source while Last.fm is a Client, the same play can arrive twice. The README claims scrobbling from many sources to one client works without duplicating tracks, and the transforms feature exists to adjust data before scrobbling, but the safe assumption is that overlap between sources is your problem to configure, not something the service can infer. The wrong-tool case is narrow listening. If every place you play music already has a working scrobbler, multi-scrobbler adds a container, a set of credentials to maintain, and an API integration per source in exchange for coverage you do not need. It is also a poor fit if you want a hosted service with no maintenance: this is a self-hosted daemon whose sources depend on third-party APIs that can change without notice.

How it differs from native Last.fm scrobbling and from server-side plugins

The direct alternative is the scrobbler built into each player or service. Last.fm's own ecosystem covers a lot of ground through official apps, browser extensions and per-player plugins. The difference is placement. A native scrobbler runs inside the player, so it works only where that player runs and only for the account signed into it. multi-scrobbler runs outside the player and authenticates to the service's API, so the same installation can cover several services and several people. The cost of that placement is that you now depend on each service's API staying stable and on your stored credentials staying valid. A second alternative is the scrobbling plugin built into a media server, for example a Navidrome or Jellyfin plugin that reports plays to Last.fm. That approach is lighter and lives where the music lives, but it is confined to that server. It will not capture a Spotify session or a Sonos speaker, and it will not forward to Maloja, Koito or ListenBrainz unless that server's plugin supports the target. If your listening is genuinely concentrated in one self-hosted server, the plugin is the smaller commitment and multi-scrobbler is redundant. If your listening is spread across servers, services and rooms, the plugin model leaves gaps that multi-scrobbler is designed to close.

Maintenance, upgrades and the MIT licence

multi-scrobbler ships frequently. The supplied release list shows 0.17.0, 0.17.1 and 0.17.2 all published within September 2026, roughly a week apart, with the last push to master on 2026-09-10. That cadence is good for fixes and bad for anyone who pins a version and forgets it, since source integrations are the part most likely to need adjustment when an upstream API shifts. Running the Docker image means upgrades are an image pull plus a restart, and the README's note that credentials are persistent suggests authorisations survive that restart, though it does not promise they survive every upgrade. Budget for re-authorising a client occasionally. The licence is MIT, which is permissive: it allows commercial use, modification and redistribution, and requires the licence and copyright notice to be preserved. That is a statement about the licence text, not advice on your situation; if you plan to redistribute a modified build or bundle it into a product, read the MIT terms and your own obligations rather than treating this paragraph as clearance. The project is not archived, and the homepage and docs site are both live per the repository metadata.

Editorial conclusion

Adopt multi-scrobbler if you play music through self-hosted servers (Plex, Jellyfin, Navidrome, MPD) or several streaming services and want one self-hosted record instead of per-app scrobbler plugins. Do not adopt it if you only listen in one app that already scrobbles natively, or if you are unwilling to run a long-lived container and re-authorise OAuth credentials when they expire. Before committing, verify three things: that your specific source appears in the Sources list and its documented authentication method still works, that your target client is listed under Clients, and whether you need the documented transforms to avoid duplicate plays when the same track is reported by two sources.

Frequently asked questions

What does multi-scrobbler do?

It is a Dockerized application that monitors your music listening activity from many services and scrobbles it to many others. It supports around thirty sources and eight clients, including now-playing support, multi-user setups, a mobile-friendly web interface with a scrobble audit trail, and queued scrobbles that retry after a network or client failure.

Can I use multi-scrobbler if I already scrobble to Last.fm?

Yes. Last.fm and ListenBrainz are both available as sources, so you can forward scrobbles from your existing profile to any other client and keep your current setup unchanged while capturing your data to a location you control.

How do I install multi-scrobbler?

With Docker images for x86 and ARM, or locally with Node.js. The repository also contains a flatpak directory and a devcontainer configuration. The container image is based on a Debian base with s6 as the process supervisor, pins Node 24.14.0 in the build stage, and maps six processor architectures.

What port does multi-scrobbler serve its interface on?

9078, published as host port to container port in the supplied compose file. That mapping has no interface prefix, so the interface and API are exposed on every host interface, and the file also mounts ./config into the container for persistent configuration and data.

How is multi-scrobbler configured?

Through environment variables or JSON. The example environment file shows the timezone, the config, data, and logs directories defaulting under ./config, and a log level setting. There are also transforms that can modify data before scrobbling using regular expression or search pattern rules.

Does installing multi-scrobbler modify its dependencies?

Yes. The postinstall script runs patch-package against a patches directory at the repository root, so installed dependency code is patched after resolution. There is also a script that runs npm ci for the application and a separate npm install inside the docsite directory during installation and during the documentation build.

Official sources

  1. FoxxMD/multi-scrobbler on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/foxxmd-multi-scrobbler.svg)](https://hysenlabs.com/projects/foxxmd-multi-scrobbler)