exportarr: a Prometheus exporter for the download stack, one instance per app
AIO Prometheus Exporter for Sabnzbd, Bazarr, Prowlarr, Lidarr, Readarr, Radarr, and Sonarr
At a glance
- What is it?
- Exportarr turns Sonarr, Radarr, Lidarr, Prowlarr, Bazarr and Sabnzbd into Prometheus metrics, and its most consequential design decision is stated in the second line of the README: it will not gather metrics from all apps at once, so you run one exporter instance per application. The configuration table is unusually good, and the disable flags are the interesting part, because they exist to tame the API calls a scrape can trigger.
- Who is it for?
- Adopt exportarr if you run the download stack and want it in the same Prometheus as the rest of your infrastructure, and you are willing to run a separate instance per application rather than one wide exporter. Do not adopt it as a single-process solution, because the README is explicit that one instance gathers one app's metrics and that every port must be unique.
- 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 134 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One exporter per app, and that is the design
Exportarr is an all in one Prometheus exporter for the family of download and media management applications: Sonarr, Radarr, Lidarr, Prowlarr, Bazarr and Sabnzbd.
The second line of the README sets the expectation before anything else: the exporter will not gather metrics from all apps at once, and you need an exportarr instance for each app. Both the container example and the command line example carry the same note that the port must be unique across all Exportarr instances.
That is a deliberate architectural choice rather than an unfinished feature, and it has a defensible logic. Each of these applications exposes a different API with different pagination and different limits, and a single process multiplexing all of them would mean one slow or broken application could affect the scrape of the others. One instance per app also means one API key per instance, which keeps the credential surface small, and it means a crash in one collector takes down one series rather than all of them.
The cost is operational. Seven applications in the stack means seven containers, seven sets of environment variables and seven Prometheus scrape entries, and the dashboard images in the repository are built around that model rather than around a single aggregated view.
The metrics themselves are served on a plain path, and the README points at the local metrics endpoint to see them, which is the standard way to confirm an exporter works before you write a scrape configuration.
The same three settings, as environment variables or as flags
There are two ways to configure an instance, and the README presents them side by side because they take the same three values.
The container form passes the port the exporter listens on, the URL of the application being exported, and the API key, with the application name as the final argument:
docker run --name exportarr_$app \
-e PORT=9707 \
-e URL="http://x.x.x.x:$port" \
-e API_KEY="$apikey" \
--restart unless-stopped \
-p 9707:9707 \
-d ghcr.io/onedr0p/exportarr:latest $appThe command line form is the same thing with flags:
./exportarr $app \
--port 9707 \
--url "http://x.x.x.x:$port" \
--api-key "$apikey"Three details in that second block matter. The application is the first positional argument, so the binary is a multi command tool with a help subcommand per application. The port is the exporter's own port, and the note repeats the uniqueness requirement. And the key is passed as a flag, which is why the configuration table offers an alternative.
That alternative is the API key file setting, a path to a file containing the key, which overrides the key variable and exists for Docker and Kubernetes secrets. It is the setting to use in any real deployment, because a key passed as an environment variable shows up in the process environment and in any configuration management system that stores the whole environment.
For orchestration there are example directories for Docker Compose and for Kubernetes, and the compose and Kubernetes examples are where the secret mounting story is actually spelled out.
The configuration table reads like a support article
The configuration section is a table with one row per setting, and the columns include the environment variable, the command line flag, a description, a default and whether the setting is required. That last column is the useful one, because it separates the two settings you must supply from the twenty you probably will not.
The required pair is the URL of the target application and its API key. The port defaults to 8081, and the interface defaults to all addresses. Logging has a level, from debug to error, and a format, console or JSON, which is the setting that matters once the exporter runs inside a cluster and something has to be parsed.
Then come the ones that change how it talks to the target. There is a setting to disable SSL verification, which is the classic escape hatch for a self-signed certificate on a home server and also the classic way to stop verifying certificates. There is a request timeout, defaulting to sixty seconds, and a form authentication option with a username and a password, for applications that put a login form in front of their API. And there is a switch for including unknown items in the queue, which is off by default.
The one setting with a legal-looking name in the table is the key file, which overrides the key itself, and it is the only one whose description mentions the deployment context, Docker and Kubernetes secrets.
Taken together, the table covers a small exporter thoroughly, and the fact that the environment variables and the flags are documented in the same table means a deployment can be written either way without cross-referencing two lists.
The disable flags are a cost model for scraping
The most interesting group in the configuration table is the set of flags that turn metric families off, because each description says what it costs.
The quality metrics flag skips the per item quality breakdowns, and the description prices it as roughly one API call per series or artist on each scrape. The episode metrics flag skips the per episode monitoring and the episode and subtitle walk, and the note is that the load scales with the size of the library. The album metrics flag skips the per album lookups, again about one API call per artist per scrape.
Then there are two flags for the endpoints that are genuinely expensive, and the reasons are different from the others. The history flag skips the history endpoint, because its total forces a full count over a history table that cannot be pruned, which is slow on instances with years of data. The wanted flag skips the wanted and missing and wanted and cutoff endpoints, whose totals also force full counts, slow on very large libraries.
So the picture is a two tier cost structure. The per item families cost a fixed number of calls per scrape that scale with the size of your library, while the count endpoints cost one very large query no matter how small the scrape.
The remaining knobs are app specific. The Prowlarr collector has a backfill switch, with a start date defaulting to the first of January 1970, which is the epoch, and a backfill that fills in historical metrics. And the Bazarr collector has a batch size for series per API call, defaulting to three hundred, and a concurrency setting for parallel calls, defaulting to ten.
For an operator this is the difference between an exporter that adds a small constant to your Prometheus and one that occasionally times out the scrape of a large library. The defaults collect everything, which is the right default for a small install and the wrong one for a decade-old library.
A scratch container with a non-root user
The Dockerfile is a good example of the kind of minimal image a small Go tool should ship in.
The build stage is a Go image on Alpine, and the first thing it installs is a set of three tools with a comment explaining each: the certificate bundle so the final stage can verify TLS to the target applications, catatonit as the container init, and the executable packer that shrinks the binary. The build itself is a static one, with the C compiler disabled, the paths trimmed, and the version, the revision and the build time stamped into the binary through linker flags, and then the result is packed with the best compression and the LZMA variant.
The final stage is scratch, meaning no operating system at all. Three things are copied into it: the certificate bundle, the init binary and the exporter itself. The port is set in the environment, the process runs as an unprivileged numeric user, and the entry point is the init binary wrapping the exporter, which is there to handle signals and reap zombies properly in a container without a shell.
The Go side of the project explains the same lean philosophy. The module declares a recent Go toolchain, and the direct dependencies are few: an environment variable parser, the Prometheus client library, the Cobra command framework with its flag package, and the concurrency helpers. Everything else in the module file is an indirect dependency of the Prometheus client.
For a tool whose job is to sit in a cluster and be scraped every fifteen seconds, that is exactly the right dependency set, and the scratch image with a non-root user is what a security scanner wants to see.
Editorial conclusion
Adopt exportarr if you run the download stack and want it in the same Prometheus as the rest of your infrastructure, and you are willing to run a separate instance per application rather than one wide exporter. Do not adopt it as a single-process solution, because the README is explicit that one instance gathers one app's metrics and that every port must be unique. Before you deploy it, decide which of the per-item metric groups you actually want, since the README prices each of them in API calls per scrape, and remember that the exporter holds an API key for the application it watches, so the credential handling matters more here than for a stateless exporter.
Frequently asked questions
What is Exportarr and which applications does it monitor?
It is a Prometheus exporter for the download and media management stack: Sonarr, Radarr, Lidarr, Prowlarr, Bazarr and Sabnzbd. It is written in Go, MIT licensed, and it exposes standard Prometheus metrics on a local metrics endpoint.
Can one Exportarr instance monitor several applications?
No. The README states that the exporter will not gather metrics from all apps at once and that you need an exportarr instance for each app, with the port unique across all instances, in both the container and the command line examples.
How do I pass the API key for the monitored application?
As the API key setting or the matching flag, and the README also documents a key file setting that points at a file containing the key and overrides the key itself, which exists for Docker and Kubernetes secrets. The target URL and the key are the only two required settings.
Why would I disable the quality or episode metrics?
Because of what they cost. The README prices the per item quality breakdowns at about one API call per series or artist on each scrape, and notes that the per episode metrics load scales with the size of the library. Flags exist for history and wanted metrics too, because their totals force full counts that are slow on instances with years of data.
How does the Exportarr container image handle TLS and privileges?
The final image is built from scratch and contains only the certificate bundle, a container init binary and the exporter, and the process runs as an unprivileged numeric user. The certificate bundle is copied in so that the exporter can still verify TLS to the target applications, and a setting exists to turn that verification off for self-signed certificates.
Official sources
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.
[](https://hysenlabs.com/projects/onedr0p-exportarr)Was this useful?