multi-scrobbler: One Scrobble Pipeline for Sources the Last.fm Apps Cannot See
Scrobble plays from multiple sources to multiple clients
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 last received commits 1 day ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE 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.
Community notes