Automated missing-media hunting and stuck-download clearing for your arr stack — with a proper security layer.
Your *arr apps (Sonarr, Radarr, etc.) grab new releases as they appear on RSS feeds — but they don't go back and search for content already in your library that never downloaded, and they won't automatically clean up stuck or stalled downloads. Sniparr handles both.
Missing content — Scans your library, finds everything marked as missing, and triggers searches in controlled batches. You set how many items per cycle and how long to sleep between runs.
Quality upgrades — Finds items below your quality cutoff and queues upgrades on the same cadence.
Stuck downloads (Swaparr) — Watches your download clients for stalled, slow, or permanently-stuck items. After a configurable number of strikes it removes the dead download and lets your *arr app find a replacement. Also catches downloads that finished but were rejected at import — these get struck and cleared so a better release can be grabbed automatically.
Indexer monitoring — Live stats, search history, and per-indexer health for your Prowlarr setup, all in one dashboard.
Sniparr started as a personal fork of Huntarr Revisited. It diverged significantly:
| Huntarr | Sniparr | |
|---|---|---|
| Scope | Added its own download pipeline (direct NZB/torrent search and send) | Deliberately removed that — your arr apps already do it better |
| Security | Basic auth | SSRF guard, CSRF tokens, signed sessions, 2FA, rate limiting, proxy/SSO auth |
| Auth options | Login only | Login, local network bypass, reverse proxy header passthrough |
| Swaparr | Strike-based removal | Strike-based + quality-rejection detection + import-failure handling |
| Prowlarr | Stats only | Stats, per-indexer history, health indicators |
| Requests | None | Use Overseerr/Jellyseerr |
The philosophy difference: Sniparr does one thing — tell your arr apps about content they're missing. It doesn't try to replace them. Huntarr added torrent and NZB client management, custom download pipelines, and calendar views for downloads. Those features overlap heavily with what Sonarr and Radarr already do natively, so Sniparr removed them to stay focused.
| App | Missing | Upgrades | Swaparr |
|---|---|---|---|
| Sonarr | ✅ | ✅ | ✅ |
| Radarr | ✅ | ✅ | ✅ |
| Lidarr | ✅ | ✅ | ✅ |
| Readarr | ✅ | ✅ | ✅ |
| Whisparr v2 | ✅ | ✅ | ✅ |
| Whisparr v3 | ✅ | ✅ | ✅ |
| Sportarr | — | — | ✅ |
Swaparr torrent clients: qBittorrent · Transmission · Deluge
Sniparr treats security as a first-class feature, not an afterthought.
| SSRF guard | Instance URLs are validated against loopback and link-local ranges before any request. localhost is blocked; Docker hostnames and RFC-1918 addresses work normally. |
| CSRF protection | All state-changing requests require a matching token — double-submit cookie, HMAC-signed. |
| Signed sessions | itsdangerous URLSafeTimedSerializer, 24-hour TTL. Changing your password invalidates all sessions. |
| 2FA | TOTP with QR setup, backup codes, and a recovery key generated at first setup. |
| Rate limiting | 5 login attempts per 60 seconds per IP. |
| Local bypass | Skip login entirely for RFC-1918 addresses — for trusted home networks. |
| Proxy / SSO | Delegate auth to Authelia, Authentik, or oauth2-proxy via a configurable header (Remote-User by default). |
services:
sniparr:
image: mrjacobarussell/sniparr:latest
container_name: sniparr
restart: unless-stopped
ports:
- "9705:9705"
volumes:
- sniparr-config:/config
environment:
- TZ=America/Chicago
- PUID=99 # Unraid default — use 1000 for standard Linux
- PGID=100 # Unraid default — use 1000 for standard Linux
volumes:
sniparr-config:
name: sniparr-configUnraid: Install via Community Applications — search for Sniparr.
Tip
Use a named Docker volume (sniparr-config) rather than a bind-mount path. On Unraid's shfs filesystem, bind mounts can cause SQLite database corruption on container restarts.
- Connect your *arr instances with an API key. URLs are SSRF-validated on save.
- Configure items-per-cycle, sleep intervals, and hourly API caps to avoid hammering indexers.
- Run — Sniparr loops: scan → trigger searches → sleep → repeat.
- Swaparr (optional) watches your download queue and removes anything stuck after N strikes.
That's it. Sniparr doesn't download anything itself — it instructs your arr apps, which handle everything through their own clients and pipelines.
Swaparr quality-rejection handling — Downloads that complete but fail import due to quality mismatch are detected via trackedDownloadState and statusMessages. Sniparr strikes them over time and removes them so a better release can be found — not just stalled torrents.
Lidarr low-match clearing — Per-instance toggle to bulk-remove stuck importPending queue items before each search cycle so Lidarr immediately re-searches rather than sitting on a bad match.
Mount-aware import retry — If a container starts before NFS/SMB mounts are ready, failed imports are queued and retried for up to ~2 hours instead of being permanently dropped.
Hourly API caps — Per-instance limits that reset every hour, preventing indexer bans during aggressive catch-up runs.
Sniparr is a ground-up project by MrJacobarussell — not a fork of anything. Several projects shaped the thinking:
- plexguide/Huntarr.io — the original missing-media hunt concept
- mrjacobarussell/huntarr — a personal fork where Swaparr quality-rejection handling, Lidarr low-match clearing, and mount-aware retry were proven out
- av1155/houndarr — security-first approach that inspired the SSRF guard, CSRF tokens, signed sessions, and proxy auth patterns
- ThijmenGThN/swaparr — the original stalled-download strike system; Sniparr's Swaparr integration is based on this work and tracks upstream improvements
No code from any of these appears in this repository.