Download Decision Webhook
Is there an existing issue for this?
- I have searched the existing open and closed issues
Is your feature request related to a problem? Please describe
I manage a multi-language library (French + original audio) and I've spent a lot of time building Custom Formats to get the right releases. It works okay for most cases, but I keep hitting limits with the scoring model:
- I can't express conditional logic. "Prefer season packs, but only if the show is done airing" doesn't translate to a score.
- Multi-language fallback chains are painful. I want French+VO first, then VO-only with French subs, then VO-only, and the priority depends on what's available, not on a fixed score.
- Size preferences vary by context. I want different size thresholds for 1080p vs 4K content, and I'd like to factor in episode count for season packs. CFs can't do math. For example, I have a "quick grab" profile for when someone asks "what do we watch tonight?"; it uses size-based CFs to get something fast. But when Sonarr searches for a full season, the size reported is the whole season, not per episode. So my size filters that work fine for single episodes become completely wrong for season packs. There's no way to say "max 2GB per episode" in a CF, you can only set absolute size limits.
- I can't consult external data. Things like checking subtitle availability on an external API, or filtering by playback compatibility for specific hardware, are just not possible in the current system.
CFs and scoring handle 90% of cases. But when they don't, the only option right now is to fork, which isn't great for anyone.
I submitted a similar request on Radarr (#11372) but wanted to bring it to the Sonarr team separately since you're different projects with different priorities.
Describe the solution you'd like
A Download Decision Override webhook that fires before the grab is sent to the download client.
The idea is simple:
- Sonarr finds candidate releases (through RSS, search, or pushed release)
- Before grabbing, Sonarr POSTs all candidates to a user-configured webhook URL
- The external service returns which release to grab (by GUID)
- Sonarr downloads that release
The webhook would be:
- Opt-in: off by default, configured per quality profile
- Fail-open: if the webhook is down, slow, or returns an error → Sonarr proceeds with its normal pick. Nothing changes for users who don't enable it.
- Simple contract: JSON payload in (releases with all their parsed metadata, quality, codec, languages, size, seeders, CF scores, etc.), GUID out.
Sonarr already does the hard work of parsing release names into structured data. The webhook just lets an external service make a decision based on that data.
What users run behind the webhook is up to them, could be a script that filters by size and seeders, something that checks subtitle availability, a rules engine, or yes, an LLM if they want. The webhook itself is agnostic.
Config location is up for discussion , could live in Settings → Download Clients, in Quality Profiles, or even as a special Custom Format type. I don't have a strong opinion on where it fits best in the UI. Whatever makes sense to the team.
- Enable: toggle (default off)
- Webhook URL: text field
- Timeout: number in seconds (default 30)
Describe alternatives you've considered
OnGrab webhook + cancel + re-grab: This is what I did first. It works but it's a hack, you're cancelling downloads after they started, which is fragile and can leave garbage in your download client. Not a real solution.
Polling
/api/v3/release: Triggers live indexer searches every time, which is expensive and slow. There's no way to query the candidates Sonarr is currently considering without triggering new searches.Custom
IDownloadDecisionEngineSpecification: Only evaluates one release at a time with no access to the other candidates. You'd need to build a stateful cache to aggregate them, which is complex and fragile.Event-based approach via
IHandle<T>: Sonarr's event handlers return void and can't influence decisions. Notifications are fire-and-forget by design.Intercepting at Prowlarr level: Would require Prowlarr changes and loses the context of which arr is requesting and why. Also doesn't have access to Sonarr's quality/CF scoring.
More Custom Formats: I've tried. I use Recyclarr, I've built dozens of CFs. Some things just don't fit in a point-based system, conditional logic, external data lookups, context-dependent preferences.
Anything else?
I have a working implementation in my Sonarr fork: github.com/AlexMasson/Sonarr. I'll be honest, I used AI-assisted coding for the implementation, so it's more of a proof of concept than production-grade code. But I've been writing C# professionally for about 10 years, so I reviewed and understood everything that went in. It's been running on my own setup for a while and it works well. It's a 1-commit diff on stable (main), isolated to:
- A new
DownloadDecisionOverrideservice in the download pipeline - Integration in
ProcessDownloadDecisions - Config properties in
ConfigService
Happy to discuss the implementation or adjust the approach if there's interest.
The reason I think this matters beyond my use case: looking at the community, people fork Sonarr/Radarr for all kinds of niche download logic tweaks. A webhook would give those users an extension point without the maintenance cost of carrying a fork, and without any burden on the Sonarr team to implement everyone's specific use case.
Source: Sonarr/Sonarr