Releases: tphakala/birdnet-go
Release list
BirdNET-Go 20260716
This is primarily a bug-fix release. It restores the range filter for arm64 (Raspberry Pi) Docker users whose species list had blown open to thousands of out-of-region species, closes an authentication middleware gap where a malformed Authorization header could let a protected handler run anyway, and fixes two database-migration edge cases that could delete a migrated database or crash-loop a fully migrated install on startup. It also adds cross-host install migration over SSH, stops the media API from showing broken audio/spectrogram players while an extended-capture clip is still being written, and corrects CPU temperature reporting on the Health page.
New Features
Cross-Host Install Migration over SSH
Moving BirdNET-Go to a new machine (for example a Raspberry Pi 4 to a Pi 5) no longer means copying files by hand and redoing the service setup. Run install.sh --migrate (or --migrate-from <host> to name the source non-interactively) on the new host and it pulls your config, SQLite database, and audio clips from the old host over SSH, then reconfigures the systemd service for the new machine while preserving your web port, TLS, metrics, and timezone settings. It verifies the old service is stopped, checks free disk space before the transfer, runs a SQLite integrity check, and never overwrites existing data on the target (any existing install is moved aside to a timestamped backup). apt + systemd Linux only; no macOS or Windows (#3934).
Security
- Auth middleware now fails closed on bad credentials. A request to an auth-protected API route carrying a malformed Authorization header or an invalid token wrote a
401but then still ran the route handler, because the abort was not propagated. The middleware now terminates the chain so protected handlers never execute after an authentication failure (#3930, fixes #3929).
Bug Fixes
Detection & Classification
- Range filter restored on arm64 / Raspberry Pi Docker. On ONNX-only arm64 images the default
rangefilter.model: latestsilently failed to load, so the active species list jumped from around 100 for your location to 6000+ and out-of-range species started showing up. Thelatestdefault now auto-selects the shipped ONNX range-filter model, restoring the same regional filtering as before with no download. If you had gotten used to the unfiltered results, out-of-range species will be suppressed again (#3933, fixes #3932).
Audio & Streaming
- FFmpeg RTSP timeouts now trigger the audio-only fallback. An RTSP source whose FFmpeg connection timed out without ever delivering data was treated as a clean end-of-stream, so the audio-only capture fallback never engaged and the stream went silent. That timeout is now detected and recorded so the fallback kicks in correctly (#3937, fixes #3936).
Media
- Audio and spectrogram players no longer break for extended-capture clips. Detections that use Extended Capture emit their database entry and live update before the audio clip finishes writing, so the media API briefly raced the file: audio and spectrogram requests returned
404, the detections list showed a broken player until a manual reload, and the transient errors spammed the logs. Clips that are still within their capture window now return503with aRetry-Afterand the player waits them out on its own, while genuinely missing clips still return404(#3946).
System & Health
- Correct CPU sensor used for the critical-temperature check. The Overview and Health pages could raise a false "Critical Temperature" alert when a non-CPU sensor read hotter than the CPU. Both pages now read the CPU thermal sensor specifically (#3941, fixes #3940).
- Health page shows CPU temperature in the configured unit. The System > Health page always printed the CPU temperature in Celsius even when the dashboard was set to Fahrenheit; it now uses the configured unit, read per request so a unit change takes effect without a restart. As a side effect of consolidating the thermal readers, the
cpu.temperaturemetric now reports the hottest valid zone, so on multi-zone or multi-socket systems it may read slightly higher after upgrade (#3945).
Database
- Migration state detected correctly on startup. A leftover marker from an old bug (PR #2165) could make a legacy database look like a fully migrated v2 database, which deleted the real migrated sidecar and dropped the app back to legacy mode. That misdetection is fixed, and the detection now discriminates by row count so a completed-v2 install that still carries empty legacy tables is recognized as v2 instead of crash-looping on startup, while a genuinely legacy database with unmigrated data is still protected (#3926, #3947, fixes #3924).
🛡️ VirusTotal Results:
BirdNET-Go 20260713
This release makes Intel iGPU acceleration usable end to end: the OpenVINO backend can now offload BirdNET and Perch inference onto an Intel integrated GPU, and the container image and installer wire the GPU render device through automatically. It also promotes the built-in Go FLAC encoder to the default and drops the FFmpeg FLAC path, closes a token leak in the HTTP access logs, and fixes RTSP sources that stopped capturing when a camera rejected an audio-only handshake.
New Features
Intel iGPU Acceleration (OpenVINO)
The OpenVINO backend added in the previous release can now offload inference onto an Intel integrated GPU, not just the CPU. On amd64 hosts with a supported Intel iGPU the container installs the Intel GPU runtime and gets access to the render device, and both the container image and install.sh pass the host /dev/dri device through so OpenVINO can see the GPU out of the box (#3888 by @xconverge, #3907).
Which models can actually use the iGPU depends on the model file, and the shipped defaults are not iGPU-ready yet:
- BirdNET ships as a TensorFlow Lite model, which cannot run on the iGPU. To accelerate BirdNET on an iGPU, switch to the fp32 ONNX model: BirdNET_v2.4_fp32.onnx.
- Perch has shipped as ONNX from the start, but iGPU offload needs the no-DFT variant, where the DFT/spectrogram stage is moved out of the model graph so the rest can run on the GPU. Pick the model for your area from Perch-v2-Models/regional; for now you have to choose the correct region yourself.
Choosing these models will move into the UI in a later release. Until then, see the OpenVINO CPU/iGPU acceleration guide in the wiki for setup steps.
Native FLAC Encoding by Default
The built-in Go FLAC encoder, previously an opt-in preview behind BIRDNET_FLAC_ENCODER=native, is now the only FLAC encoder for both saved detection clips and BirdWeather soundscape uploads. FLAC (including EBU R128 loudness normalization) now encodes entirely in Go with no FFmpeg dependency; FFmpeg is still used for MP3, AAC, and Opus and for clip download transcoding. On a host without FFmpeg, a FLAC export setting now produces real .flac files instead of being silently downgraded to WAV (#3900).
Security
- HLS/media tokens scrubbed from access logs. Signed HLS and media stream tokens embedded in request URLs were being written to the HTTP access log; they are now redacted from both the path and the query string there, closing a gap left by the earlier v2 API log scrubbing (#3861).
Bug Fixes
Audio & Streaming
- RTSP sources recover when audio-only capture fails. After the audio-only RTSP handshake was introduced, some cameras that cannot set up the audio track in isolation stopped capturing entirely. Those streams now fall back automatically to the full RTSP stream (video is still discarded after decode), while cameras that already worked are unchanged (#3905).
Installer & Diagnostics
- Installer runs
systemd-analyze verifywith sudo, so service-file validation no longer fails on permission errors during install (#3894). - Support dump tails logs fairly, giving each log file a fair share of the tail budget so a few large logs no longer crowd the others out of the dump (#3904).
🛡️ VirusTotal Results:
BirdNET-Go 20260712
This release brings hardware-accelerated inference through a new OpenVINO backend that runs BirdNET v2.4 and Perch v2 roughly twice as fast on a Raspberry Pi 5 and on Intel iGPUs, paired with a new AI Models & Inference page that shows what each model is doing in real time. It also adds an experimental BirdNET-Pi import so you can bring your detection history over from a Pi, a redesigned Analytics section with a batch of new pattern and exploration charts, and per-stream audio gain for RTSP sources. On the reliability side, USB sound cards now survive a reboot without losing capture, RTSP streams open correctly on FFmpeg 4.x (Debian 12), and the "Ignore this species" checkbox on a False Positive review finally works. Security hardening rounds it out: the public detection stream no longer leaks internal source details to anonymous clients, and HLS stream tokens are scrubbed from logs.
New Features
AI Models & Inference
BirdNET-Go now includes a native OpenVINO inference backend as an opt-in alternative to the ONNX Runtime CPU path. On ARMv8.2 CPUs with native half-precision (Cortex-A76, for example the Raspberry Pi 5) it runs the BirdNET v2.4 classifier at f16 roughly twice as fast as the CPU path, and it can also offload Perch v2 and the bat embedding extractor onto an Intel iGPU. A new hot-reloadable birdnet.backend preference (auto, onnx, openvino) selects it, the OpenVINO runtime is bundled in the container images, and any failure (missing library, unsupported CPU or model) falls back cleanly to ONNX Runtime, so default behavior is unchanged where OpenVINO does not apply (#3547, #3549, #3551, #3609, #3812).
A new AI Models & Inference page under System shows the detected hardware, the active inference backends and versions, and a card per loaded model with its identity, backend, quantization, species count, live latency and real-time-factor sparklines, approximate RAM use, and a "last heard" diagnostic feed. The page updates live and refreshes automatically when models are added, removed, or reloaded (#3563, #3566, #3571, #3577, #3585, #3603).
arm64 container images now ship a faster INT8 ONNX model by default instead of TensorFlow Lite; existing arm64 configs keep working with no migration, and custom .tflite models still load (#3544, #3864).
BirdNET-Pi Import (Experimental)
A new Import/Export page under System can import your detection history from an existing BirdNET-Pi birds.db. A guided wizard walks through selecting the source, choosing database-only or database-plus-audio mode, and then shows live progress with running, complete, cancelled, and failed states, plus a link to the imported detections when it finishes. Imports are idempotent, so re-running never creates duplicates. For containers, a new external-media mount lets you plug in a USB drive, SD card, or file share and have it appear inside the container without a restart (#3655, #3657, #3660, #3663, #3665, #3737, #3868).
This feature is marked Experimental in the UI. Native (non-container) import uses a permission-elevation flow for protected source files, and audio import is still being finalized. Please report problems on GitHub.
Redesigned Analytics (Preview)
The Analytics area has been reorganized into task-grouped Explore and Patterns sections with a batch of new visualizations: a seasonal density heatmap (date against time of day), a who-sings-when species ridgeline, a dawn-chorus onset tracker, a nocturnal activity clock, a per-species confidence distribution, a species accumulation curve, arrival and departure phenology, an acoustic succession streamgraph, and a year-over-year tracker (#3589, #3608, #3610, #3611, #3618, #3622, #3626, #3629, #3634, #3638, #3648, #3741, #3742, #3744).
Some of this is still in progress: the Weather, Soundscape, and Review analytics views and the source/microphone filter are hidden in this release and will return once they are finished (#3867).
Per-Stream Audio Gain
RTSP and network audio streams now have their own input-gain control in stream settings, mirroring the sound-card gain slider, and it takes effect without a restart. This release also fixes the case where a stream URL accidentally configured as a local sound card produced a live-audio failure with no explanation; such entries are now moved to the correct place automatically and the error message is actionable (#3779).
Cleaner UI When Clip Export Is Off
When clip export is disabled, no audio is saved, so the audio players and spectrograms that used to render empty or broken are now hidden across the dashboard, detections list, detail view, search, and the review modal, and cards collapse to a compact layout. Historical clips stay playable if you later turn export back on (#3760 by @fophillips, #3765).
Installer Reconfiguration
install.sh is now re-runnable: a new "Reconfigure settings" option lets you change the web port, TLS and access mode (direct, Let's Encrypt, or behind a reverse proxy), metrics exposure, audio device, timezone, and locale on an existing install, then regenerates the service and restarts with a config backup and rollback on failure. Fresh installs no longer bind ports 80, 443, and 8090 by default (they are now opt-in), so they stop colliding with an existing web server, and updates preserve your existing bindings (#3675, #3685, #3879).
Restart-Required Notifications
Settings that cannot take effect until a restart (web server and TLS, database, logging, and TLS certificate operations) now show a clear restart banner with the specific reason, instead of saving silently with no indication (#3531).
Smaller Extras
- User-editable model catalog. The model catalog is now a JSON file in your config directory that you can edit; it is seeded on first run and, if you leave it untouched, refreshes automatically on upgrade (#3605).
- Native FLAC normalization (opt-in preview). With the experimental native encoder enabled (
BIRDNET_FLAC_ENCODER=native), detection-clip saves with loudness normalization now normalize entirely in Go with no FFmpeg dependency. The default FFmpeg path is unchanged (#3777). - Low-memory runtime detection (foundation). BirdNET-Go now detects a constrained memory limit at startup (including container cgroup caps) and applies conservative heap and allocator backstops, controlled by a new
lowmemory.modesetting (auto,on,off). On systems with ample memory it is inactive and changes nothing (#3533).
Security
- Anonymous clients no longer see internal source details. The public detection SSE stream was sending the raw audio-source display name (which can embed an RTSP host or credentials) to unauthenticated subscribers; they now receive only a stable source id, while authenticated clients are unchanged (#3726).
- HLS tokens and secrets scrubbed from logs. Request and error logging in the v2 API recorded raw URL paths and query strings, which meant live HLS stream tokens were being written to logs; these are now redacted (#3727).
- Session cookie Secure flag follows real TLS state. The session cookie's Secure flag is now derived from whether TLS is actually in effect (#3783).
Bug Fixes
Audio & Streaming
- USB sound cards survive a reboot. Capture is now matched to a stable USB hardware id instead of the ALSA card index the kernel reassigns at boot, so a sound card no longer stops working after a reboot until you re-select it in Settings. This was the most-reported audio issue (#3688, #3697).
- RTSP streams open on FFmpeg 4.x (Debian 12). The FFmpeg connection-timeout flag is now selected per FFmpeg version, fixing RTSP capture that failed to start on FFmpeg 4.x (#3560 by @mvanhorn, #3658).
- Sample-rate dropdown populates when adding a new audio source (#3680).
- Clip exports no longer collide thanks to a unique temp file per export (#3556).
Spectrograms
- Bat spectrograms show the ultrasonic range again. The bat frequency profile was disabled by a malformed filter argument, so bat clips rendered in the 0-12 kHz bird view; it is fixed and re-enabled (#3529 by @alexbelgium).
- Fallback spectrograms render in color. When clip generation falls back to FFmpeg (for example MP3 clips on native Windows), the default style now renders colorful instead of black and white (#3847 by @pelazas).
Detections & Review
- "Ignore this species" on a False Positive now works. The checkbox silently did nothing because of a field-name mismatch; ticking it now actually adds the species to the exclude list (#3815 by @iamrans0m00).
- Review saves no longer duplicate comments, and you can now unlock a detection from the review form (#3859).
- Detection cards no longer overlap or get clipped on mobile (#3719 by @alexbelgium, #3729 by @alexbelgium).
- Missing dashboard thumbnails fall back to an alternate image provider instead of showing nothing (#3816).
- Banner descriptions preserve line breaks (#3814 by @iamrans0m00).
- Top-species ordering is stable for species with equal detection counts, so the dashboard list no longer reshuffles between refreshes (#3830).
- Species rarity uses your local calendar day, so "new species today" and rarity status are correct across time zones (#3820).
Species & Multi-Model
- No more duplicate species when running multiple models. Detections are now collapsed to a canonical scientific name at ingestion, so BirdNET and Perch reporting the same bird under different names no longer show up twice or fire a spurious "new species" alert. Range-filter and inclusion matching are alias-aware as well (#3728, #3725).
- Perch v2 non-bird classes are recognized by the privacy and dog-bark filters and by image lookups (#3584).
- Settings species exclude list is canonicalized to scientific names so exclusions match reliably (#3692).
Integrations & Weather
- MQTT accepts scheme-less broker addresses in the TLS a...
Release Manifest
Auto-generated, machine-readable manifest of the latest BirdNET-Go release on each channel (stable, nightly, beta). Do not delete; consumed by the in-app update checker. Stable URL: https://github.com/tphakala/birdnet-go/releases/download/manifest/manifest.json
Nightly Build nightly-20260615
The headline of this release is species name localization for every model: detections from Perch v2 and BattyBirdNET used to show as raw scientific names, and now the majority of species resolve to proper common names in your configured language, thanks to an embedded OpenFauna dataset that is now the authoritative naming source across the dashboard, analytics, search, and species settings. This release also adds an opt-in Private Mode that locks the whole UI and API behind login, three new contributor features (a New & Returning Species widget, source badges on detections, and sortable species tables), and an important security fix that stops source-IP spoofing through forwarded headers on directly-exposed instances.
New Features
Localized Common Names for Every Model
Species detected by secondary models such as Perch v2 and BattyBirdNET previously displayed as raw scientific names, because those models only ship scientific-only labels. BirdNET-Go now resolves names through a vendored, embedded OpenFauna dataset (40+ locales), so the large majority of species, birds and bats alike, show proper common names in your configured species language across the dashboard, analytics charts and tables, detection detail, search, the species settings pickers, and CSV exports. Force-include and exclude lists, as well as search, now also accept localized common names for these scientific-only species (so a Finnish "mopsilepakko" resolves to Barbastella barbastellus). This is a display and search overlay only: MQTT, BirdWeather, notifications, the public API, RSS, and the stored database names continue to use the server-configured locale (#3404, #3406, #3407, #3450, #3452, #3454, #3460, #3461, #3464, #3468, #3469, #3504, #3506).
Two notes for upgraders: OpenFauna is now the naming authority, so for the default en-uk locale a handful of species names shift from IOC British forms to eBird/American forms (for example "Common Magpie" becomes "Eurasian Magpie"), and a search for the old name no longer matches. Separately, per-visitor browser-language localization (showing names in each visitor's own UI language) is wired in but ships off by default; it stays dormant behind a kill switch pending a dedicated per-visitor species-language preference that is independent of the UI chrome language (#3463, #3474).
Private Mode
A new Security.PrivateMode toggle (default off) locks the entire dashboard and v2 API behind authentication, for operators who do not want any read-only UI or API reachable from the internet. With it on, every endpoint except the small login-bootstrap allow-list requires authentication, and the SPA shows a full-screen login. It is strictly additive: with the toggle off, the existing guest-friendly behavior is unchanged, and the setting hot-reloads without a restart (#3122 by @TeTeHacko).
Re-Alert on Rising Confidence
Detection alert rules can now notify again when a species crosses a higher configured confidence step, scoped to the species and novelty episode, instead of being suppressed for the whole cooldown window. A rare bird that starts as a low-confidence detection and grows more convincing will now alert again at the higher step (#3288 by @keithkml).
New & Returning Species Widget
An optional dashboard widget surfaces species carrying a novelty indicator (new lifetime, new this year, or new this season) for the selected day, with a confidence pill, detection count, and a "last seen N days ago" gap for returning species. It renders nothing on quiet days and adds no extra network requests (#3376 by @alexbelgium).
Source Badges on Detections
Detections now show which microphone or RTSP source heard each bird, across detection cards, tables, the detail view, analytics, and the currently-hearing card. Search gains a source filter to match (#3101 by @TeTeHacko).
Sortable Species Tables
The analytics Species page columns are now click-to-sort, with the sort order persisted across refreshes and kept in sync with the filter dropdown (#3325 by @alexbelgium). The species settings Custom tab was also redesigned from a flat, header-less list into a sortable, searchable table matching the sibling Active tab (#3508).
Precipitation in Weather Data
The yr.no, OpenWeather, and Wunderground providers already collected a precipitation amount and a high-level condition category, but both were dropped before reaching the database. They are now persisted and exposed through the weather API and the detection-detail weather panel (#3495).
Detection Drops on System Health
Detections dropped because the classifier results queue was full were previously only visible in logs. The System Health page now surfaces these drops with windowed counts and trend indicators, so users on constrained hardware can see when they are losing detections, and how many (#3497).
Native FLAC Encoder (Preview, opt-in via BIRDNET_FLAC_ENCODER=native)
This release adds an experimental pure-Go FLAC encoder and EBU R128 audio-normalization path that removes the FFmpeg dependency for detection-clip exports and BirdWeather soundscape uploads. With the BIRDNET_FLAC_ENCODER=native environment variable set, FLAC clips and BirdWeather uploads are encoded in-process, which avoids the FFmpeg subprocess failures (encode timeouts, broken pipes, missing or misconfigured ffmpeg) that recur on resource-constrained and container deployments.
This is off by default and experimental. With the variable unset, the existing FFmpeg path runs unchanged and is byte-for-byte identical to before. The native path is gated so it can earn confidence in the field before becoming the default; there is no settings or UI for it yet (#3483, #3502, #3512).
Security
- Forwarded client-IP headers now require a trusted proxy -
CF-Connecting-IP,X-Forwarded-For, andX-Real-IPwere honored from any peer, so a client on a directly-exposed instance could forge its source IP, which feeds login rate limiting, subnet-bypass auth, and request logs. These headers are now trusted only from loopback/private peers by default, plus a new hot-reloadableSecurity.TrustedProxiesCIDR list (the reserved value"cloudflare"expands to Cloudflare's edge ranges). Upgrade note: a reverse proxy that connects from a public IP must be added toTrustedProxiesfor forwarded headers to be honored again (#3393). - Open-redirect hardening on login - post-login redirect targets are now validated and base-path-aware, so a crafted redirect cannot send users off-site after authentication (#3360).
- Weather provider logs no longer leak secrets - API keys and request coordinates are now scrubbed from provider error logs and wrapped errors, and endpoint schemes are validated (#3448, #3451, #3456).
Bug Fixes
Audio & Streaming
- Per-stream channel selector showed blank after reload - an unset channel mode came back as an empty string that the form's default did not catch, so the dropdown showed "Select..." after every reload. The control now adapts to the source (selector for multi-channel, a note for mono), surfaces the detected stream format, and no longer triggers a needless stream restart on an empty-vs-explicit downmix transition (#3357).
- iOS/iPad Safari played clips silently - when the shared AudioContext was still suspended, the players routed audio into the suspended graph, which on iOS permanently silences the element. Clips now play through the native output while suspended and attach the Web Audio graph only once the context is running (#3511).
- Stream test gave a generic error for audio-less streams - testing a URL with no audio stream now reports that specifically instead of a generic connection failure (#3429 by @kv1sidisi).
- Audio exports now use dual-pass loudness normalization for more consistent clip levels (#3367).
Authentication
- Basic auth and OAuth settings now hot-reload - changing them in Security settings takes effect immediately without a server restart (#3379).
- Post-login redirect preserves the query string - you now land back on the exact page you requested, including its query parameters (#3359).
- OIDC reliability and UX - per-issuer retry lifecycle for OIDC, OAuth login flow logged to the security module, and clearer allowed-users guidance in the settings UI (#3390, #3384).
Dashboard & Analytics
- Mobile dashboard now uses a single-column layout instead of a cramped multi-column grid (#3274 by @keithkml).
- Detection search now matches common names, not just scientific names (#3385).
- Analytics timezone handling - charts and SQL now bucket dates, years, and hours by the configured timezone instead of UTC, and analytics queries apply a consistent timeout and return 408 on deadline (#3475, #3476, #3467).
- Assorted UI fixes - the species image popup aligns to the row top in the above position, a permanent horizontal scrollbar was removed from the daily stats grid, and several dropdown, fetch-race, search-filter, and audio-playback edge cases were fixed (#3498, #3505, #3494).
Weather
- Weather polling recovers after a settings change - the polling lifecycle, hot-reload recovery, and backoff state machine were hardened so weather updates resume correctly after settings are changed at runtime (#3453).
Infrastructure & Platform
- Rootless container startup - the container no longer tries to link system timezone files (which fails under a rootless or arbitrary user); it reads the
TZenv var directly and falls back to UTC with clear guidance when the timezone cannot be resolved (#3369 by @bo0tzz). - systemd host timezone - the systemd service generator now detects the host timezone via
timedatectland/etc/localtime(#3351).
Internationalization
Nightly Build nightly-20260601
This release fixes stereo RTSP streams that stopped detecting birds after nightly-20260524, and adds per-stream audio channel selection so you can pick which microphone channel (left, right, or both) each stream uses for detection. Support dump submission from Settings > Support works again (the previous timeout was too short for Raspberry Pi and slow connections). Alert rules can now match against species lists and trigger on new or returning species. A round of multi-model stability fixes makes running BirdNET alongside Perch much more reliable.
New Features
Per-Stream Audio Channel Mode Selection
You can now choose which audio channel each stream uses for bird detection: left, right, or downmix (both channels mixed together). This matters because many IP cameras send stereo audio where only one channel carries the actual microphone signal. Mixing both channels together can reduce detection accuracy due to phase interference between the left and right signals.
A new dropdown in stream settings (both when adding and editing streams) lets you pick the mode. An "Analyze Channels" button captures a few seconds of audio and shows a visual comparison of the energy levels on each channel, with a recommendation for which one to use. If a stereo source is still set to downmix, an orange warning banner appears on the stream card suggesting you select a single channel instead (#3286, #3287, #3300).
Alert Rule Enhancements
Alert rules now support "in list" and "not in list" matching, so you can create a single rule like "notify me only if the species is NOT in my common-bird list" instead of creating dozens of separate rules. A new species novelty system also tracks when each species was last seen, letting you create rules that trigger on genuinely new species (never detected before) or returning species (back after a period of absence) (#3267, #3275 by @keithkml).
Smarter Health Diagnostics
The System Health page is now better at distinguishing a brief glitch from a real problem. Instead of simple error counters, health checks evaluate whether issues are transient or sustained, whether they are getting worse or improving, and how many hours in the evaluation window were affected. The detail panel shows these signals visually with trend indicators and pattern badges, making it easier to decide whether something needs attention (#3289, #3290, #3293).
Lower Memory Usage from Audio Resampling
The audio resampler now reuses memory buffers instead of allocating new ones for every audio frame. In practice, this noticeably reduces BirdNET-Go's total memory consumption and garbage collection overhead, especially on low-powered devices like Raspberry Pi where memory is limited (#3285 by @anyasabo).
Bug Fixes
Audio & Streaming
- Stereo RTSP streams stopped detecting birds - a regression in nightly-20260524 caused stereo RTSP streams to skip the mono downmix step when the source sample rate already matched the target (both 48 kHz). The audio pipeline received interleaved stereo samples but treated them as mono, effectively halving the sample rate. Visible symptoms: audio sounds slowed down, upper third of the spectrogram is black, and detection rates drop to zero. Fixes #3278, #3277 (#3283).
- RTSP streams had no connection timeout - the FFmpeg flag for RTSP socket timeouts was incorrect (
-timeoutinstead of-stimeout), so streams had no protection against hanging connections during the TCP connect phase (#3287). - HLS live stream played back at quarter speed for high sample rate sources - when capturing at 192 kHz (bat detection), the HLS pipeline skipped an internal downsampling step, causing the browser audio player to play back at roughly 4x slower than real time (#3347).
Range Filter & Multi-Model
- Perch detections bypassed geographic range filter - with the default range filter setting, Perch species were not filtered by location, allowing out-of-range species to appear in detections and notifications (#3276 by @keithkml).
- Active Species table empty after uninstalling a model - removing Perch v2 or BirdNET v3.0 could leave behind stale config that silently disabled the range filter entirely, causing detections to run unfiltered with no warning in the UI (#3324).
- Species count showed ~14,800 species with multi-model - when running BirdNET alongside Perch, the Active Species / Current Species count ignored the range filter threshold for non-primary model species, displaying every species in the database instead of only those in your geographic area (#3326).
- Stale range filter config persisted after model uninstall - even after the runtime was fixed, the saved config could still show incorrect status in the Species page and heatmap. The config now self-heals on startup (#3327).
- Duplicate species in analytics with multi-model - insights pages (new arrivals, dawn chorus, phantom species, expected species) showed duplicate entries when both BirdNET and Perch detected the same species (#3294).
Model Reload Stability
- Crashes and incorrect results during model reload - several race conditions could cause crashes, panics, or stale data when reloading, uninstalling, or reinstalling models while detection was running. Model metadata is now captured atomically during reload, and settings access is synchronized across all concurrent readers (#3329, #3333, #3340, #2933 by @anyasabo).
Health Diagnostics
- Health status showed "Healthy" when no data was available - the system now correctly reports "Unknown" when diagnostic results are empty, instead of falsely reporting a healthy state (#3308).
Infrastructure & Platform
- Container startup failed on Kubernetes/OpenShift - running under an arbitrary user ID (common in rootless containers and OpenShift) caused startup failures because the system could not look up user information. Container detection now uses a reliable fallback (#3266 by @bo0tzz).
- Let's Encrypt certificates lost on every restart - TLS certificates were stored only in memory, so each restart requested a new certificate from Let's Encrypt. This could hit rate limits and cause temporary HTTPS outages (#3319 by @brycesub).
- Support dump uploads timing out on slow connections - submitting a support dump from Settings > Support could fail on Raspberry Pi or slow networks because the upload exceeded the default 30-second HTTP timeout. The timeout is now 120 seconds (#3301).
- Unnecessary image lookups wasting API calls - the background image refresh was retrying species that were already confirmed to have no image available, and included species from prediction models that had never actually been detected (#3305 by @keithkml).
- Noisy error reports from Wikipedia rate limiting - temporary Wikipedia API throttling was generating unnecessary error reports in Sentry; these are now suppressed since they resolve on their own (#3309).
- "Error opening /proc/self/cgroup" message on macOS - a harmless but confusing error message appeared on non-Linux platforms during container detection (#3193 by @anyasabo).
- Build setup failed on Raspberry Pi - architecture detection in the Taskfile was incorrect for ARM platforms (#3192 by @anyasabo).
Nightly Build nightly-20260524
This release fixes a critical regression where RTSP streams with sample rates below 48 kHz (typical IP cameras send 8-16 kHz audio) cut in and out after the bat detection changes in nightly-20260523. All streams are now probed at startup so resampling only happens when needed. This release also adds time-windowed health evaluation with sparkline visualizations, SQLite corruption detection with auto-recovery at startup, and completes settings hot-reload coverage for the remaining 5 settings that previously required a restart.
New Features
Time-Windowed Health Evaluation with Sparkline Visualization
Health diagnostics no longer evaluate lifetime counters. A past burst of errors previously marked the system as Critical forever until restart; checks now evaluate configurable time windows (15m to 7d, default 1h). The System Health page is redesigned to match the System Overview visual language: a status metric strip replaces the old hero card, diagnostics auto-run on page mount, and counter-based checks show inline SVG sparklines (24 hourly bars, colored by status) with expandable detail panels. The window selector persists to localStorage. 22 new i18n keys fully translated across all 15 locales (#3249).
Complete Settings Hot-Reload Coverage
Five settings categories that were saved to disk but required a restart to take effect now hot-reload at runtime: Log Deduplication, RTSP Health monitoring, MQTT HomeAssistant discovery, System Monitoring, and HLS LiveStream. This brings the hot-reload TODO count from 5 to 0: every setting changed through the UI now takes effect immediately (#3254).
SQLite Corruption Detection at Startup with Auto-Recovery
A synchronous PRAGMA quick_check now runs at startup after migration. When index-level corruption is detected (common from power loss on SD cards), BirdNET-Go attempts automatic recovery via REINDEX. If recovery fails, the system continues in degraded mode so headless users keep web UI access. A corruption flag is latched to suppress duplicate Sentry event floods (prevents the 244+ duplicate events seen in production), and a persistent notification with actionable recovery guidance is sent to the user. A new DatabaseIntegrityCheck appears in the health diagnostics system (#3246).
Security
- Temp file paths hardened against symlink attacks - Predictable temp file paths across datastore, API prerequisites, and log rotation are replaced with
os.CreateTemp(random name +O_EXCL). Backup files and archives now use0600permissions instead of theos.Createdefault. Database connection pools are properly closed when post-Open()initialization fails (#3248).
Bug Fixes
Audio & Streaming
- RTSP streams with sub-48 kHz sample rates cut in and out - The bat detection changes in nightly-20260523 removed FFmpeg's
-ar/-acoutput resampling flags for all protocol streams, which broke cameras that send 8-16 kHz audio since the pipeline expects 48 kHz. All streams are now probed viaffprobeat startup to discover actual sample rates. Resampling is applied only when the source rate differs from the target: sub-48 kHz sources get resampled up, 48 kHz sources skip resampling, and high-rate bat sources preserve their ultrasonic content. A newSourceSampleRatefield carries the probed rate through the full pipeline. Fixes #3255 (#3256). - Model reload used stale settings, locale changes required restart -
ReloadModel()read from a stalebn.Settingspointer, so changing the locale or thread count via the UI had no effect until a full restart. All sub-methods now see a fresh settings snapshot. Five stale settings reads in HLS streaming are also fixed (#3253). - Duplicate ORT notifications on range filter reload - The v3 geomodel path bypassed the early ONNX Runtime availability check, causing repeated Sentry events and bell notifications on every range filter reload when ORT was unavailable. A single check at the top of model initialization now guards both paths (#3245).
Health Diagnostics
- Health check endpoint could hang indefinitely -
runChecksspawned goroutines with 10s per-check contexts and then calledwg.Wait()unconditionally. If a check ignored its context (e.g.,gopsutilsyscalls), the/api/v2/system/diagnostics/runendpoint blocked forever. A channel-based approach now respects an overall timeout with a 100ms grace period, returningStatusUnknownfor unfinished checks. Multi-result slices are defensively copied to prevent data races (#3251).
Nightly Build nightly-20260523
The headline change in this release is that bat detection now works on network audio streams. Previously, bat models only ran against locally attached sound cards because the streaming pipeline forced every stream to 48 kHz, destroying the ultrasonic content bats are recorded at. Streams now discover their actual sample rate at connect time, so a 192 kHz PCM RTSP feed from an AudioMoth or USB ultrasonic mic on a remote Raspberry Pi can drive a bat model directly. Support dumps now bundle a database schema snapshot, application event log, and deployment context for much better remote troubleshooting. A series of database integrity fixes resolves upgrade failures where startup silently fell back to legacy mode, lost detections, or rejected MariaDB authentication. Non-bird species in the Perch v2 label set now show up under the correct genus, family, and taxonomic class in the species tree.
New Features
Bat Detection Over Network Audio Streams
Bat detection previously required a sound card attached directly to the BirdNET-Go host with ALSA exclusive mode; RTSP and other network streams were unusable because the audio pipeline hardcoded streams to 48 kHz, which is far below the 256 kHz capture rate bat models expect and which throws away all ultrasonic content above ~24 kHz.
Streams now probe their actual sample rate, codec, and channel count with ffprobe at connect time, and the buffer pipeline carries that rate end-to-end. A working RTSP feed from a remote AudioMoth or a USB ultrasonic microphone on a separate Raspberry Pi (the community example used a 384 kHz feed) can now drive a bat model directly with no sound card on the BirdNET-Go host.
The settings UI gains a Test Stream button next to the URL field on both the add-stream form and existing stream edit cards. It calls the new POST /api/v2/streams/test endpoint and shows the probed sample rate, codec name, and a bat-compatibility badge inline. When a stream uses a lossy codec (AAC, Opus, MP3) a dedicated warning explains that lossy compression destroys ultrasonic content even when the sample rate is high enough; only raw PCM or FLAC over RTSP can preserve the frequencies bat detection needs. Save and Add are gated on a successful test, with specific localized errors for unsupported URL schemes, blocked destinations (SSRF protection blocks loopback, link-local, metadata, and unspecified IPs), connection failures, and timeouts. The model checkbox list shows a bat-stream-requirements warning whenever a bat model is selected on a stream source so users see the hardware/codec constraints before they save (#3229, #3230, #3236, #3237).
Genus, Family, and Class Metadata for Perch v2 Non-Bird Species
Perch v2's label set has always included insects, amphibians, mammals, reptiles, arachnids, mollusks, and other non-bird taxa, but the embedded genus_taxonomy.json only carried bird taxonomy. Non-bird detections lacked genus, family, and class metadata, so the species tree, classifier metadata, and grouping in the UI fell back to hardcoded Class: "Aves" / Phylum: "Chordata" and produced incorrect hierarchies for everything outside birds. The taxonomy database is now extended via GBIF Backbone Taxonomy (4,110 additional species; 93% match rate), growing from 2,375 to 3,720 genera, 254 to 495 families, and 11,324 to 15,434 catalogued species. GetSpeciesTree() resolves the correct Class and Phylum dynamically (Arthropoda for insects/arachnids, Mollusca for snails/clams/squid, Cnidaria for hydrozoans, Platyhelminthes for trematodes, Chordata for vertebrates) so non-bird Perch v2 detections show up under the right branch of the tree. This is metadata only: Perch v2 itself still identifies the same species it always did, but they now display with correct taxonomic context. README and detection-pipeline docs updated to drop the inaccurate "bird species only" framing of Perch v2 (#3209).
Enhanced Support Dumps
Support dumps now include three new diagnostic artifacts to make remote troubleshooting practical without back-and-forth requests for additional logs:
database_info.jsoncaptures the complete database schema for SQLite and MySQL: table schemas, column definitions, indexes, row counts, integrity check, foreign key violations, migration state, app metadata, WAL/SHM sizes, and SQLite PRAGMA diagnostics. Each sub-collection has its own timeout (2-30s) so partial failures never kill the dump (#3213).app_events.jsoncontains the last 30 days of application events (max 1,000 entries): startup, shutdown, version changes, hot-reloads, model loads, settings saves with per-key diffs, migration state transitions, range filter updates, schema repair, and notification delivery attempts. Settings save events scrub sensitive values (passwords, tokens, API keys, certs) before persisting. Events are backed by a new persistent app event repository with a 90-day retention cutoff and 10k row cap (#3215, #3216).deployment_info.jsoncaptures working directory, systemd service file (with environment variable scrubbing), data directory listing, and/proc/1/mountinfofor container bind mounts. Detects Docker, Podman, LXC, and systemd-nspawn. Useful for diagnosing fresh-install detection issues where a database exists but isn't visible to the new install (#3217).
Database startup also gains structured decision logs at every code path: fresh_install, v2_restart, legacy_mode, stale_sidecar_fallback, v2_corrupted, and migration state outcomes, with a safety scan that warns about nearby .db files when a fresh install is detected.
A new standalone tools/db-doctor/db-doctor.py script (zero dependencies, Python 3) diagnoses and repairs BirdNET-Go SQLite databases offline. The read-only mode runs eight checks (integrity, schema version, schema contamination across ai_models/labels/detections/daily_events, foreign keys, migration state, clip path extensions, and a database fingerprint); --fix recreates contaminated tables, recovers orphaned label references, resets stuck migration states, REINDEXes corrupted indexes, and repairs clip extensions against the filesystem. All repairs run in transactions on top of an atomic SQLite backup; lock detection prevents running while BirdNET-Go is active (#3212, #3223).
Periodic Pipeline Stats Logging
Two always-on info-level log summaries print every 5 minutes to make the detection pipeline diagnosable from regular logs. Pipeline stats report per source/model: inference count, raw classifier results, results that passed filter, max confidence seen, and the effective threshold. Audio level stats report per source: average, minimum, and maximum levels, zero percentage, and clipping percentage. Both suppress zero-activity periods to avoid log spam. Motivated by GitHub Discussion #3220 where users reported zero detections after model changes with no log evidence (#3226).
Model Selection Recommendation Banners
The model checkbox list on audio source configuration (sound cards and streams) shows contextual notification banners. When both BirdNET and Perch are installed but only BirdNET is enabled, an info banner recommends enabling both models for best species coverage. When only Perch is selected, a warning banner advises lowering the confidence threshold to 0.50 for meaningful results. Banners only appear when both model families are available; if only one is installed, no banner is shown. All 15 locales include native translations (#3228).
Automated Root-to-User Installation Migration
Users who previously ran sudo ./install.sh and got blocked by the root guard now get an automated migration path. When a root install is detected, the installer offers a 3-way prompt: migrate (recommended), fresh install, or cancel. The migration stops the existing service, copies data to the user's install location, fixes file ownership, validates the config and SQLite integrity, and cleans up the old systemd files. Pre-flight checks cover source validity, destination emptiness, and disk space with a 10% safety margin. On failure, the partial copy is removed so retry attempts aren't blocked. Silent mode (--silent) auto-migrates without prompting. Triggered by user reports of being unable to update after a Proxmox root install (#3191).
A separate change converts the hard root-check block to a soft block with a --force-root flag for users who understand the tradeoffs (containers, minimal setups). With --force-root, a one-line warning is shown and the install proceeds (#3206).
Health Diagnostics: FFmpeg and Sox Tool Checks
A new tool availability check in the Config category of the System Health page reports whether FFmpeg and Sox binaries are present at runtime, including the FFmpeg version string. The check reads paths from the live audio settings, so it stays accurate across hot-reload (#3203).
Security
- TLS certificate writes are now transactional with atomic temp-file rename, backup/restore for delete handlers, and cert file cleanup on settings save failure. Prevents partial writes from leaving corrupted certs on disk and orphaned deletions when settings save fails. Delete handlers are serialized under the settings mutex to eliminate the race between backup and remove (#3208).
- SoxPath validation added before exec at all five Sox call sites in the spectrogram generator, rejecting empty, relative, and proxy-contaminated paths. Mirrors the existing FFmpeg path validation as defense-in-depth against command injection via settings (#3200).
Bug Fixes
Database & Schema Integrity
- Silent legacy fallback masked missing v2 columns - When GORM
AutoMigratesilently failed to add a column, every insert produced "table has no column named X" errors, and the legacy fallback hid the failure. The schema validator now runs a missing-column check afterAutoMigratethat returns `ErrV2Sc...
Nightly Build nightly-20260519
This release introduces an audio liveness watchdog that automatically recovers from silent audio capture failures, a system health diagnostics page with 31 checks across 8 categories, and multiselect with bulk actions for the detections list. New Help & Support pages guide users through bug reporting with support dump generation. ONNX Runtime availability is now checked across the model gallery, install pipeline, and health system so users get clear feedback when the runtime is missing. A large batch of thread safety, TOCTOU race, and panic safety fixes improves stability across the audio pipeline and API layer.
New Features
Audio Liveness Watchdog with Tiered Recovery
A new per-source watchdog detects when audio capture silently dies (e.g., USB audio hardware failure) and orchestrates automatic recovery through a tiered state machine: single-source restart, full app restart, then terminal failure with notification at every step. Previously, a silent audio thread death could go undetected for hours with no error logged and no alert fired. The watchdog exposes per-source health state via GET /api/v2/health/audio and its check interval and thresholds are configurable through new settings (#3106, #3112).
System Health Diagnostics
A new System Health page under Help runs 31 diagnostic checks across 8 categories (system, audio, analysis, streams, database, network, config, logs) in parallel with per-check timeouts. Results are grouped by category with color-coded status pills. Reports can be copied to clipboard or exported as JSON. Checks that are not yet wired to live data show a "Skipped" status rather than misleading results. The diagnostics backend caches reports by UUID for retrieval (#3132, #3133, #3135, #3137, #3185, #3186, #3187).
Detection List Multiselect and Bulk Actions
The detections list gains a selection mode with per-row checkboxes, shift-click range selection, and a header checkbox for page-level select/deselect. A Gmail-style "select all N matching" banner appears when the entire page is selected. Supported bulk actions include delete, mark correct, mark false positive, lock, and unlock, with a confirmation modal and toast feedback. New batch API endpoints under /api/v2/detections/batch/ handle the backend operations (#3119).
Help & Support Pages with Guided Bug Reporting
A new Help & Support page at /ui/help provides cards for Report Bug, Ask a Question, and Quick Links. The guided Report Bug flow at /ui/help/report-bug walks users through providing system information, describing the issue, generating a support dump, and opening a GitHub issue. The sidebar gains a collapsible Help section and the header settings menu adds Report Bug and Ask a Question links (#3130).
ONNX Runtime Availability Gating
Perch, BattyBirdNET, and geomodel features are now gated behind an ONNX Runtime availability check with five defensive layers: the model gallery grays out incompatible models with a warning banner, the install API rejects ONNX-dependent installs, the orchestrator emits a high-priority bell notification on load failure, already-installed models that lost ORT show a red warning, and a new ort_availability health check reports version and library path. Users no longer see cryptic init errors when ORT is missing (#3153, #3155).
Species Heatmap Grid API (Preview)
A new GET /api/v2/range/heatmap endpoint computes species probability grids across a map viewport for all 48 BirdNET weeks, returning a compact binary payload (BNHM format). The endpoint uses batch geomodel inference to compute thousands of grid points in a single ONNX session call, with an in-memory LRU cache and generation-counter invalidation. A dedicated multi-threaded ONNX session and IoBinding tensor reuse eliminate per-batch allocation overhead. This is the backend foundation for the upcoming Migration Explorer feature; no frontend visualization ships in this release (#3105, #3111).
Security
- Container entrypoint command injection - replaced unsafe
eval echowith safe parameter expansion in both Docker and Podman entrypoints to prevent command injection via crafted model paths. Added.onnxand.csvto model file permission setup. Brought Podman entrypoint to feature parity with Docker: rootless mode detection, pre-flight checks, gosu privilege dropping (#3159). - Install script sed injection - added
sed_escape_replacement()helper that escapes\,|, and&before interpolation into sed commands, preventing injection via crafted RTSP URLs, coordinates, or password hashes. Added input validation for lat/lon, audio format, locale, and port range. Updated config generation to target the new multi-source format (#3160).
Bug Fixes
Audio Pipeline
- Panic recovery in audio dispatch and shutdown - drain and stop routes now wrap Close() calls in individual recover blocks, preventing a misbehaving consumer from crashing the caller goroutine. Added serialization mutex for restart, reconfigure, and watchdog escalation to prevent conflicting router states (#3110).
- Quiet hours not enforcing for RTSP streams - the scheduler was never wired to the stream manager (missing
SetStreamManagercall), and used raw URLs instead of the runtime-generated hashed source IDs (rtsp_<hex>). Streams were silently never stopped or started (#3127 by @iamrans0m00). - Default audio channels not applied consistently - some stream start paths skipped the defaultChannels fallback, causing channel count mismatches (#3143).
- Default bit depth fallback missing - added defaultBitDepth fallback and fixed a buffer leak in ReconfigureSource (#3146).
- Model assignment changes not detected during hot-reload - the analysis engine now detects when model-to-source assignments change and logs the new mapping (#3183).
Alerting
- Notifications always sent to both bell and push - the alert dispatcher ignored the action's target field and dispatched to all channels. Bell-only rules now skip push, push-only rules skip persistent storage, and per-target deduplication prevents duplicate dispatches (#3136).
Thread Safety & Resource Leaks
- Logger module not registered for classifier - orchestrator and nighttime scheduler logs were silently lost because the "birdnet" module was not in logger defaults. Also fixes unbounded overrun tracker map growth when sources are removed (#3104).
- Model reload panic could leak mutex - wrapped entry.mu in closure with defer. Fixed uninstall ordering so config updates before range filter reload (#3114).
- Float32Pool leak on inference panic - deferred pool return so the buffer is reclaimed even if inference panics (#3115).
- Context.Canceled Sentry noise - filtered context cancellation errors and non-finite duration values from Sentry reporting (#3128).
- Controller.engine not thread-safe - converted to atomic.Pointer to eliminate data races (#3141).
- Race in handleSettingsChanges goroutine - eliminated concurrent access to shared state during settings change handling (#3145).
- controlChan panic on shutdown - guarded channel sends to prevent send-on-closed-channel panics during graceful shutdown (#3149).
- TOCTOU races in API handlers - snapshot Processor and BirdImageCache at request entry to prevent mid-request pointer swaps. Deduplicated database stats queries with consistent locking (#3154, #3156).
Dashboard & Frontend
- CSRF token blocking logout - added
/api/v2/auth/logoutto CSRF skip list so logout works when the token expires on long-lived pages like live stream (#3117). - Notification "Illegal constructor" error - use ServiceWorkerRegistration.showNotification() when a Service Worker is active, falling back to the Notification constructor otherwise (#3117).
- Clipboard error in popup terminal - added catch for unhandled NotAllowedError when the document loses focus (#3117).
- Empty statusText in dashboard errors - added fallback for browsers that return empty status text (#3125).
- Fullscreen crash on Safari - added typeof guard with webkitRequestFullscreen fallback (#3129).
- Pre-renderer shutdown race - removed channel close that could panic on concurrent Submit() (#3129).
- Hemisphere detection at equator - replaced
latitude != 0proxy with the existing LocationConfigured boolean flag so equator locations work correctly (#3129). - crypto.randomUUID on non-HTTPS - centralized with try/catch fallback for insecure contexts (#3152).
- StatusPill readability - improved contrast and sizing for better readability across themes (#3182).
Query & Sorting
- Hourly and species queries ignoring sort order - routed these query types through advanced search so user-selected sort columns take effect (#3139).
- Hourly default sort and cross-type filters dropped - made query routing aware of hourly-specific defaults and filters that span query types (#3142).
- Silent filter dropping in unified query path - consolidated all query routing into a single path to prevent conditions where filters were silently ignored (#3147).
Database
- FLOOR() incompatible with SQLite - replaced with CAST(AS INTEGER) for cross-database compatibility (#3107).
Classifier
- Rarity scores showing "Very Rare 0%" for non-English locales - species comparison used full labels with locale-specific common names, which never matched geomodel labels that use English names. Fixed all three comparison points to match on scientific name only (#3170).
Internationalization
- Czech locale added (#3124 by @TeTeHacko).
Nightly Build nightly-20260515
This release delivers a 2.3x inference speedup for Google Perch v2 on default configurations and fixes several range filter issues that could cause incorrect species filtering after geomodel installation. The model gallery gains a standalone BirdNET Geomodel v3.0 card, and the Analysis settings page is reorganized into dedicated bird and bat sections with a new confirmation-based false positive filter for bat detections.
New Features
Perch v2 Inference Performance
Multi-model inference is now serialized so only one model runs at a time, eliminating memory bandwidth contention on resource-constrained hardware. The ONNX Runtime thread default is fixed to use all available CPU cores instead of falling back to single-threaded execution when threads=0. On a Raspberry Pi 5, this cuts default-config Perch v2 inference from 630ms to 270ms, a 2.3x improvement (#3088).
BirdNET Geomodel v3.0 Model Gallery Card
BirdNET Geomodel v3.0 is now available as a standalone entry in the model gallery with proper attribution and license metadata. The gallery Available tab is split into "Acoustic Classifiers" and "Geomodels" sections, making the layout extensible for future model types. Installed geomodel cards show the upstream URL and license badge (#3091).
Analysis Settings: Bird and Bat Sections
The Analysis settings page is reorganized into dedicated Bird Detection and Bat Detection sections with independent change tracking. A reusable false positive filter component uses stepped dot indicators and i18n-ready level names. A warning banner appears when the false positive filter is set to Off, encouraging users to enable filtering (#3097).
Bat Detection: Confirmation-Based False Positive Filter
Bat detection gains its own confirmation-based false positive filter, separate from the bird filter and the ultrasonic validation filter introduced in the previous release. The filter uses three levels (Off, Moderate, Strict) matched to the bat model's fixed 50% overlap. Bat models now correctly use settings.Bat.Threshold instead of falling back to the BirdNET threshold, preventing legitimate bat detections from being filtered when the BirdNET threshold is set higher (#3094).
Bug Fixes
Range Filter
- Species list not refreshed after geomodel install - installing a geomodel from the model gallery reinitialized the ONNX backend but never rebuilt the species inclusion list. The processor kept using the stale list from startup until the next daily rebuild at midnight (#3086).
- "Allow species without range data" toggle had no effect - enabling PassUnmappedSpecies did not add unmapped classifier species (~314 for BirdNET V2.4) to the inclusion list. The species count shown in the UI stayed the same and unmapped species were silently blocked (#3099).
- Geomodel auto-selection overriding user config - an explicit user-configured range filter model (e.g.,
rangefilter.model: legacy) was silently replaced by auto-selection logic. Now gated on empty model field so explicit config is respected (#3087). - Duplicate species in range filter output - species appearing in both range filter results and include/config lists were counted twice. Added deduplication in the legacy path (#3087).
Multi-Model Analysis
- Buffer overrun monitor using BirdNET-specific calculations for all models - the monitor hardcoded BirdNET v2.4's 3-second clip length and overlap settings, producing false overrun warnings for Perch v2 (5-second clips with 695ms inference, well within its 2.5-second window). Now uses each model's actual buffer interval (#3085).
Thread Safety & Resource Leaks
- Labels race during model reload -
NumSpecies()andLabels()could read label data concurrently withloadLabels()mutations during model reload. Added mutex protection and defensive copy (#3100). - Settings clone missing Models.Installed - the
Installedslice was shared between cloned and original settings, allowing concurrent modifications to corrupt active config (#3100). - SSE progress handler leak on rapid install/reinstall - model install and reinstall handlers now clean up the previous SSE subscription before reassigning, preventing connection leaks (#3100).
- RebuildRangeFilter missing read lock - added read lock for consistency with all other range filter endpoints (#3100).
- SaveYAMLConfig file descriptor leak - added deferred close for panic-safe cleanup. On Windows, the leaked descriptor prevented temp file removal (#3100).
Configuration
- Season date comparison ignoring actual dates -
isDefaultSeasonConfigurationonly checked season names, silently overwriting user-customized start dates with system defaults. Now compares both names and dates (#3100).
Internationalization
- 491 untranslated keys translated - translated English fallback values to native translations across all 13 non-English locales, reducing untranslated instances from 1,205 to 714 (remaining are technical terms, brand names, and universal abbreviations) (#3096).
🛡️ VirusTotal Results: