- Run frame gathering for finished review items on a thread so per-frame ffmpeg calls don't stall the embeddings maintainer
- Share one path between live and regenerated review descriptions
- Stop padding review start and end times in place, which widened the stored review item
- Lock timestamp expiry in EventsPerSecond since update() and eps() now run on different threads
* Validate MQTT TLS verification options before client startup
* Test MQTT configuration recovery with authentication available
* Cover both MQTT TLS verification values in safe-mode recovery
* Use a documentation address in MQTT regression tests
* Skip MQTT TLS validation when MQTT is disabled
* Simplify MQTT TLS validation regression coverage
---------
Co-authored-by: Peter Kay <dougle.peter.kay@googlemail.com>
* pin debug replay to one recording stream
Debug replay stream-copied the merged VOD playlist into one mp4. When main had gaps that sub filled, the clip switched streams mid-file, and a camera with an H.265 main and an H.264 sub produced an mp4 labeled H.264 that also held HEVC packets. The replay camera's decoder then failed and the watchdog killed ffmpeg. Replay now follows the clip download rule: it pins the playlist to main and only falls back to sub when the range has no main recordings.
* choose the replay stream with the vod coverage resolver
Stream selection counted a main row that only touched the range, while the pinned playlist served nothing for it, so replay failed instead of using the sub footage. Selection now uses resolve_coverage, the same resolver the pinned vod and export use.
* fix sub label filter for non-ascii names
The sub_labels filter lowercased the requested name in Python but the stored value with SQLite's LOWER(), which only folds ASCII. Cyrillic and other non-ASCII names never matched, so filtering by a face name returned no events. Both sides are now lowered in SQLite, which keeps ASCII matching case-insensitive and non-ASCII matching exact.
* cover events/search in sub label filter test
* report ownership scan progress
The ownership scan printed nothing until it finished, which took 30+ minutes on large recordings volumes and looked stuck. It now logs a running count of checked and mismatched entries every 30 seconds.
* check the scan clock on every entry
* fix autotracking movement time prediction and recorded move times
Movement time prediction multiplied the fitted intercept by the saved zero-step calibration time instead of 1, so predictions didn't match the regression. In absolute zoom mode, a pan/tilt followed by a zoom recorded the zoom's timestamps against the pan/tilt distance, because _zoom_absolute resets the PTZ start and stop times. The pan/tilt times are now captured before the zoom runs.
* predict velocity and zoom size for objects approaching the autotracked camera
The velocity check required both box corners to move in the same direction, but the corners of an approaching object diverge, so its velocity was rejected and zeroed and the camera aimed where the object had been. That check is removed, and the existing magnitude, delta, and variance checks still reject noise. The zoom size prediction fit area against epoch time with no intercept, which returned roughly the mean area instead of a forecast. It now scales the target box by the growth the corner velocities predict over the movement time.
* keep predicted target box positive and add regression tests
A shrinking object's predicted size could reach zero, so the relative zoom ratio divided by zero and sent a NaN zoom to the camera. The predicted size is now floored at 1 px. Tests also cover the movement time intercept and the pan/tilt timestamps that absolute zoom overwrites.
The VOD manifest used to find the keyframe-snapped clip start was built from the live annotation offset while the playing clip used the offset from when the event opened. Each offset step fetched a manifest for a different clip, so the seek mapping drifted: the video jumped forward about one GOP every second of offset and flickered while each new manifest loaded. The manifest now uses the same stable source offset as the playlist
Users can swap in their own go2rtc binary at /config/go2rtc or point ffmpeg.path at a custom build, and either can explain stream behavior that looks like a Frigate regression. The install section now reports a custom_go2rtc boolean and an ffmpeg enum (default, bundled, custom) for the configured global path, so no version strings or path text leave the install.
* write migrated config atomically
Config migration rewrote config.yml in place with open("w") after each step, so nginx's get_nginx_settings.py, which starts alongside frigate, could read an empty file, get None from yaml.load, and crash on config.get. Each step now writes to a temp file with the original mode and os.replace's it into place.
* keep config owner and handle file bind mounts in migration writes
os.replace failed with EBUSY when config.yml was a file bind mount, as in the documented --validate-config command, and the replaced file lost its original owner when Frigate ran as root. The write now copies in place on EBUSY and restores the original owner when permitted. Tests cover a failed dump leaving the original config and the bind-mount fallback.
* follow config symlinks in migration writes
* Request FP16 TensorRT engine for ONNX detector with device Tensorrt
get_ort_providers only enables trt_fp16_enable when requires_fp16 is
passed, and the ONNX detector never passed it, so device: Tensorrt
always built an FP32 engine. USE_FP16=False still disables FP16.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Make TensorRT FP16 opt-in via USE_FP16 only
Drop the unused requires_fp16 parameter from get_ort_providers and decide
trt_fp16_enable from the USE_FP16 environment variable alone, defaulting
to false. Revert the ONNX detector change and document USE_FP16=true for
device: Tensorrt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Drop the TensorRT docs line
The stock image ships only the TensorRT runtime, not the builder
libraries needed to create engines, so the instructions were misleading.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* strip intel media driver on install
The manually built iHD_drv_video.so was installed with full debug info, making it 513 MB in the image instead of 41 MB stripped. Installing with install/strip removes about 240 MB from the compressed amd64 image.
* remove rjsf 6.11.0 dependabot hold
The hold covered the GenAI form refilling the saved model after a provider switch. That was a GenAIModelWidget bug that rjsf 6.11 exposed, and it was fixed with the 6.11.1 bump in #24901, so no rjsf version needs holding.
* strip intel media driver after install
install/strip skipped iHD_drv_video.so because media-driver installs it with install(PROGRAMS), not as a target. Strip it directly instead.
* bump dev docs version in header
* attest published images with github build provenance
Published images carried unsigned BuildKit provenance, so nothing tied an image digest to the commit it was built from. Each published image (the default multi-arch build and the six variants) now gets an actions/attest provenance attestation pushed to GHCR, verifiable with gh attestation verify. Release tags are skopeo copies with the same digest, so they're covered too. Storage records are off because they require an org-owned repo.
* Add on-demand Frigate+ API key validation
The Frigate+ settings page reported the API key as validated whenever it
matched the expected format, without ever checking it with the server.
- Clarify the status text to say the key matches the expected format
- Add PlusApi.validate_key(), which requests a token from Frigate+ and
reports the key as valid, invalid, unreachable, or not set; server
errors and timeouts are not reported as an invalid key
- Add an admin-only POST /plus/validate endpoint and regenerate the API spec
- Add a "Validate with Frigate+" button that shows the result inline
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E4iDiZE2b3tVFVYyZrfZde
* Validate Frigate+ key asynchronously and keep cached token on bad replies
- Use aiohttp for the validation request so the endpoint awaits it
instead of blocking a worker thread
- Only replace the cached token when the reply has a string accessToken
and numeric expires; otherwise report unreachable so an unexpected
response can't break later Frigate+ requests
- Test against a local aiohttp server, covering timeouts, connection
failures, non-JSON replies and unusable token shapes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E4iDiZE2b3tVFVYyZrfZde
* Honor proxy settings when validating the Frigate+ key
aiohttp ignores HTTP(S)_PROXY unless trust_env is set, so validation
reported Frigate+ as unreachable on installs that need a proxy while
other Frigate+ requests still worked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E4iDiZE2b3tVFVYyZrfZde
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* check go2rtc stream sources on the internal port
auth() returned admin for internal port requests before the go2rtc src check ran, so anyone who could reach port 5000 could send an unknown src to /api/ws, and go2rtc created a stream from it and started its producer, including ffmpeg sources with #raw= arguments. The internal port now rejects any src that isn't an existing stream, the same as the external port, and still skips the per-camera role checks.
* reject go2rtc stream names that can inject transcode parameters
live.transcode.source names a go2rtc stream that is spliced into an ffmpeg:{name}#video=h264 source, and stream names were never validated, so a stream named with #raw= parameters, whitespace, quotes or a ${VAR} reference added its own ffmpeg arguments. New stream names with these characters are rejected through the API, transcode.source fails validation when its stream name has them, and startup skips the generated transcode stream.
* only export allowlisted environment_vars
apply_config_env_vars wrote every unprefixed environment_vars key into os.environ and exported every FRIGATE_ key, so a config could set LD_PRELOAD or LIGHTER_ANE_EP to load a library into Frigate or its children, or set FRIGATE_RUN_AS_ROOT to turn off the ffmpeg.path writable-tree guard. Only the documented names are now exported, each with a value check, and a name the container already sets is never overwritten. FRIGATE_ keys still feed substitution, but only FRIGATE_JWT_SECRET is exported. Anything else logs a warning naming the key.
* don't trust live stream names as existing go2rtc streams
* don't run a config ffmpeg.path as root at boot
The frigate and go2rtc run scripts probed "$ffmpeg_path" -version as root before dropping privileges, and resolve_ffmpeg_path only refused runtime-user-writable paths when frigate itself was a root service. In the default mode uid 1000 could set ffmpeg.path to a /config directory, plant bin/ffmpeg there, and get root on the next restart, and under FRIGATE_ROOT_SERVICES=go2rtc a root go2rtc used that path as its ffmpeg bin. The probe now runs as the service user whenever the service drops privileges, and resolve_ffmpeg_path refuses writable paths for whichever service will run the binary, returning the resolved path so a symlink can't be retargeted after the check. go2rtc falls back to the bundled build's libavformat version if its user can't run the custom build.
* resolve the full ffmpeg path under granular root
* remove nginx-secure-token-module from the nginx build
Kaltura deleted the nginx-secure-token-module repo, so the tarball download in build_nginx.sh returned a 404 and any build without a cached nginx layer failed. This drops the module and its secure_token directives from the vod location.
* use sub_filter to pass vod playlist args to segment URLs
Home Assistant signs vod playlist URLs with authSig and needs it on every init, segment, and index URL in the playlist. sub_filter appends the request args to the three URL endings vod writes, giving byte-identical playlists to the old secure_token output.
Currently translated at 89.9% (695 of 773 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.4% (472 of 522 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (141 of 141 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.2% (1260 of 1396 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (74 of 74 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 89.1% (107 of 120 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (50 of 50 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.5% (240 of 265 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 89.9% (695 of 773 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 64.4% (181 of 281 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.2% (1260 of 1396 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.2% (1260 of 1396 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 89.9% (695 of 773 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.4% (472 of 522 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 64.4% (181 of 281 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.2% (1260 of 1396 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (50 of 50 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.5% (240 of 265 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (129 of 129 strings)
Update translation files
Updated by "Cleanup translation files" add-on in Weblate.
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 89.9% (695 of 773 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.2% (1265 of 1401 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (129 of 129 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 96.8% (62 of 64 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.2% (1265 of 1401 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (129 of 129 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 90.5% (240 of 265 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 98.5% (67 of 68 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (500 of 500 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (129 of 129 strings)
Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 100.0% (500 of 500 strings)
Update translation files
Updated by "Cleanup translation files" add-on in Weblate.
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: 蘭蘭露 <flandretw@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/audio/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/common/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-camera/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-dialog/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/components-filter/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-cameras/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/config-global/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/objects/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-classificationmodel/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-events/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-motionsearch/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-settings/zh_Hant/
Translate-URL: https://hosted.weblate.org/projects/frigate-nvr/views-system/zh_Hant/
Translation: Frigate NVR/Config - Cameras
Translation: Frigate NVR/Config - Global
Translation: Frigate NVR/audio
Translation: Frigate NVR/common
Translation: Frigate NVR/components-camera
Translation: Frigate NVR/components-dialog
Translation: Frigate NVR/components-filter
Translation: Frigate NVR/objects
Translation: Frigate NVR/views-classificationmodel
Translation: Frigate NVR/views-events
Translation: Frigate NVR/views-motionSearch
Translation: Frigate NVR/views-settings
Translation: Frigate NVR/views-system
stop_all_ffmpeg called communicate() on the detect ffmpeg even when the capture thread was still reading stdout, which happened on every ffmpeg, record, and record_sub config restart and when a camera stalled during a stop. The two readers could buffer duplicate frames without bound or hang the stop. When the capture thread is still alive, it now terminates and waits, then kills, so the live thread drains the pipe and ffmpeg can finish its segment. Disable and shutdown still use stop_ffmpeg.
* Measure Gemini image-token cost instead of using the pixel heuristic
Review descriptions size their frame budget from the provider's
estimate_image_tokens(). Gemini did not override it, so the base
~1-token-per-1250-pixels heuristic was used: about 46 tokens for a 320x180
preview frame. Gemini 3 models actually bill about 1100 tokens per image
regardless of size, so the 24000-token image budget let Frigate send one
frame per second of the review item (e.g. 90 frames for a 90 s alert)
instead of ~21, and review descriptions cost roughly 4x more than intended.
Probe the model with the free count_tokens endpoint, the same way the
llama.cpp provider measures its mmproj, and cache the result per image
size. Fall back to the base heuristic if the request fails.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Bound Gemini image-token probes and back off after failures
estimate_image_tokens() runs on the enrichment thread, and count_tokens was
using the client's defaults: a 120 s timeout and 3 attempts on 429/5xx. A
hung endpoint could stall review processing for minutes per review, and a
rate-limited key retried on every review of an unmeasured size.
Give the probe a 5 s timeout with no retries, and after a failure use the
heuristic without probing again for 5 minutes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Update docs to note that Gemini charges roughly-flat token cost regardless of video resolution
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add analytics opt-in setting, prompt notice kind, and notice watermarks
* Add the analytics report schema
* Add the analytics state file
* Add the install and hardware analytics collectors
* Add the detection analytics collector
* Add the cameras analytics collector
* Add the features analytics collector
* Add the health analytics collector
* Build analytics reports from the section collectors
* Add the analytics report transport
* Send the daily analytics report from the main process
* Add the analytics preview API
* Generate the analytics schema and check it in CI
* Record the image variant in each Dockerfile
* Show the analytics preview in telemetry settings
* Document anonymous analytics
* change wording
* fixes
* update network requirements docs
* adapt analytics to free-form model scenes, split notice counts, and peewee 4
* fixes
* change log levels
* docstrings
* docstrings
* honor file-only analytics opt-outs and skip pre-consent notices
An opt-out saved through the YAML editor's "Save only" or a hand edit never reached the live config, so reports kept going out under the old install ID until a restart. The reporter now reads telemetry.analytics from the config file when a report is due, validated with TelemetryConfig so yes, on, and 1 still count as consent, and an opt-out there deletes the state file and skips the send. The first report under a new install ID also carried every notice since the counters started, including ones from before the opt-in, so a fresh state file now resets the notice watermarks before the report's snapshot.
* take the notice baseline at opt-in instead of the first send
The watermark reset ran at the first send attempt, so notices raised between the opt-in and that send, up to 45 minutes after a startup, were absorbed into the reset and never reported. The reporter now writes the new install ID and resets the watermarks as soon as it sees consent without a state file.
* report notice counts cumulatively from a database baseline
Moving watermarks after each accepted send kept the install ID and the notice baseline out of step: pre-consent notices went out, notices raised before the first send were dropped, and a send that finished after an off/on toggle overwrote the new identity's baseline. health.notices now carries cumulative counts since the install ID was created. Creating an ID copies the lifetime counts into the existing reported_* columns before the state file names it, and nothing is written after a send, so the backend diffs consecutive reports per install ID.
* write held notice repeats before the analytics baseline reset
Repeats of batched kinds like failed_login wait in memory until the stats emitter flushes them, so a baseline reset taken while some were held left them out, and the next flush counted those pre-opt-in repeats as post-consent. The reset now writes held repeats to the notice history under the same lock before copying the counts.
* seed detector inference speed from the first inference
The average started at 0 so idle detectors read 0, but that made every detector's speed climb from 0 for its first couple dozen inferences after a start. Detectors now use the same InferenceSpeed helper as enrichments, so the first inference seeds the average and idle detectors still read 0.
* don't calibrate or skip capability checks when autotracking is enabled at runtime
Enabling autotracking from the UI on a camera that had been disabled for missing FOV relative movement or MoveStatus skipped both checks because ONVIF was already initialized, then ran calibration on the object processing thread and hung waiting for a motor stop that never came. Setup now runs the capability checks every time, only calibrates at startup, stops tracking the triggering object when setup disables the camera, and publishes the OFF state so the toggle reflects it.
* only show settings reset buttons when the reset can succeed
Reset to Global and Reset to Default delete the section from config.yml, and the delete raised a KeyError (HTTP 500) when the key wasn't in the file. Camera live sections always read as overridden because the backend fills in live.streams per camera, and the global Reset to Default button showed for every section, including ones the user never wrote. Global reset now only shows when the section differs from its schema defaults, ignoring fields the backend resolves at runtime (ffmpeg and record export hwaccel_args, audio filters). Camera live overrides skip streams, ffmpeg overrides skip inputs, and reset is hidden for camera ffmpeg and detection models, where deleting the section can't produce a valid config. Birdseye modes uses a plain default so the schema carries it.
* Added an e2e spec covering reset visibility for default and customized global sections, the runtime-resolved fields, camera live overrides, and camera ffmpeg
* Don't block the event loop in OpenAI chat streaming
* Close OpenAI stream opened after the caller disconnected
* Show GenAI worker thread usage in system metrics
* Remove GenAI thread stats per review
* Use Starlette iterate_in_threadpool for OpenAI stream
* miscellaneous fixes
- keep base path in recording share links
- reject non-positive scale on recordings/unavailable, which looped forever on the event loop
- reject negative vod event padding, which cleared has_clip
- clamp negative preview gif/mp4 offsets
- don't delete exports that are still in progress
- hash on unknown login usernames so timing doesn't reveal valid users
- include the first minute of the events time-of-day filter
- show an error when the push subscription is refused
- don't wipe an unnamed known plates entry when Add is pressed again
- use elapsed hours for export last N hours so DST doesn't shift the range
* fix live audio settings and trigger highlights
- start each camera group's audio from that group's saved settings instead of merging every group
- don't clear the previous trigger's highlight timeout when another trigger fires
* address review feedback
- Discard the export row when an export fails before or during ffmpeg, so it doesn't stay in progress until a restart
- Skip the empty thumbnail path when discarding a failed export
- Measure preview clip duration from the clamped start
- Default live player volume to 1 when the group has no saved setting
- Clear the unsaved registration message when notification registration fails
- Keep a highlight timer per trigger
- Remove the severity order_by in /review, which the start_time order_by replaced
* Hold pandas 3.1 until numpy 2
* fix two-way talk shortcut and detail stream active item after camera switch
* show already running message when a media sync is in progress
* pick the earliest overlapping preview for preview gif and mp4
* unmute camera audio when starting two-way talk from the shortcut
* remove password strength meter and fix confirm password feedback
The strength meter still scored against the old 8 character and character class rules, so any password with a digit, like test1234, showed a full green "Very Strong" bar next to the failing 12 character requirement. The meter is gone and the length checklist is the only feedback. The password field's form message duplicated the checklist, and editing the password never revalidated the confirm field, so a fixed mismatch kept showing "Passwords do not match". Editing the password now revalidates the confirm field once it has a value, and both dialogs show a live match/mismatch indicator in place of the confirm form message.
* add configurable ttl for active alert notifications
Notifications sent while an alert was active always used a TTL of 0, so the push service dropped them if the device wasn't reachable at that moment and users only received the notification sent when the alert ended. A new `ttl` notifications option, settable globally or per camera, lets the push service retry these notifications for that many seconds. It defaults to 0, and the settings UI warns that a non-zero value can deliver stale notifications.
* make notification ttl a global advanced setting
- Read `ttl` from the global notifications config and hide it on the camera form
- Show it under Advanced Settings on the Notifications page
- Remove extra padding that misaligned the Notifications cards with the rest of the form
- Shorten the ttl warning
* tweaks
* use enum instead of raw seconds value
* Bump protobuf
Bumps the pip-trt-security group with 1 update in the /docker/tensorrt directory: [protobuf](https://developers.google.com/protocol-buffers/).
Updates `protobuf` from 3.20.3 to 5.29.6
---
updated-dependencies:
- dependency-name: protobuf
dependency-version: 5.29.6
dependency-type: direct:production
dependency-group: pip-trt-security
...
Signed-off-by: dependabot[bot] <support@github.com>
* keep amd64 tensorrt protobuf on 7.36
Dependabot moved every protobuf pin in docker/tensorrt to 5.29, but the security alerts only cover the aarch64 pin. On amd64 that would downgrade protobuf below what TensorFlow 2.21 requires (>=6.31.1), and the image would build with a pip warning and fail at import tensorflow. This keeps the aarch64 change to 5.29.6, which is the same change verified on #24350 (onnx 1.14.0 and TensorFlow 2.19 both work on it).
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
* keep base path in logout redirect
* store manual event sub labels as verified objects
Manual events created with a sub label were stored in the review item as "label: sub_label", so review previews and collapsed History cards showed a generic icon, the review label filter missed them, and the sub label never reached sub_labels for chips, notifications, or GenAI prompts. The object processor now publishes the label and sub label separately, and the review maintainer stores them as label-verified plus a sub_labels entry, the same as tracked objects.
* only expire snapshots for events that still have one
Snapshot expiry selected every event older than snapshot retention, including events whose snapshot was already deleted, so with snapshot retention shorter than alert/detection retention the same missing files were unlinked again every cleanup cycle until the event row expired. That was nearly free on local disk but caused constant metadata load on network shares. The expiry queries now filter on has_snapshot so each snapshot is deleted once.
* check ownership before stopping a camera watch from chat
The stop_camera_watch chat tool cancelled the active VLM watch job without checking who started it, so any authenticated user could cancel another user's job by calling /chat/completion directly. The tool now uses the same admin-or-creator check as DELETE /vlm/monitor, and chat-started jobs record their creator so non-admins can still stop their own.
* Added a test that calls `_execute_start_camera_watch` and checks `start_vlm_watch_job` receives the caller's username, so removing that argument now fails it.
* Update live.md
Adds to docs a note that disabling V8 optimisations can cause live view issues
* Update docs/docs/configuration/live.md
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
go2rtc expands ${NAME:default} over the raw config text before parsing it, and falls back to the inline default when NAME is unset, so a stream source like ${NOPE:exec:<cmd>} passed the exec gate and go2rtc then ran the command. On master the API accepted the plain form, and startup accepted the ${{...}} form because .format collapsed it to ${...} after the check would have caught it. Any stream source containing ${ is now restricted unless GO2RTC_ALLOW_ARBITRARY_EXEC is set, the same as exec sources.
* restrict go2rtc ffmpeg and ngrok options without arbitrary exec
The GO2RTC_ALLOW_ARBITRARY_EXEC checks only looked at go2rtc.streams, so an admin could save a config with a custom ffmpeg.bin or ngrok.command and run any command as the go2rtc user after a restart. go2rtc builds every ffmpeg: source into a command that starts with ffmpeg.bin, and it runs ngrok.command at startup. A custom template also brought back arbitrary ffmpeg arguments, since a stream can reference any template key with #video=<name>.
config/save and config/set now reject any added or changed key under go2rtc.ffmpeg or go2rtc.ngrok unless arbitrary exec is enabled. Keys already in the saved config are left alone, the same as stream sources. At startup, ffmpeg.bin is always Frigate's ffmpeg and ngrok is dropped unless arbitrary exec is enabled. Templates already in the config file, such as the documented vaapi global, keep working.
* reject ffmpeg paths with spaces, quotes or shell characters
ffmpeg.path was used as-is when absolute, and several ffmpeg commands are built as strings and split on spaces before running. A path like `/bin/sh -c <cmd>;#` ran a shell command instead of ffmpeg in the preview and export processes, and in go2rtc through the birdseye restream exec source. The path is now validated as a version alias or an absolute path of plain characters, so config/save and config/set reject an unsafe value. resolve_ffmpeg_path falls back to the default ffmpeg for one, and the go2rtc startup script prints an error.
Since 0.18.2, every request that went through /auth logged an uninitialized "go2rtc_stream_proxy" variable warning, because only the go2rtc stream locations set that variable. The warning is now turned off in the /auth location, and the header value sent to /auth is unchanged.
2026-10-16 07:44:39 -05:00
434 changed files with 20487 additions and 3574 deletions
@@ -36,7 +36,7 @@ When reviewing code, do NOT comment on:
- **Formatting**: Ruff (configured in `pyproject.toml`)
- **Linting**: Ruff with rules defined in project config
- **Type Checking**: Use type hints consistently
- **Testing**: unittest framework - use `python3 -u -m unittest` to run tests
- **Testing**: unittest framework - use `python3 -u -m frigate.test` to run the suite in parallel groups
- **Language**: American English for all code, comments, and documentation
- **Punctuation**: Do not use em dashes in documentation, comments, or strings; reword with standard punctuation (commas, colons, parentheses, or separate sentences)
import AnalyticsFields from "@site/src/components/AnalyticsFields";
import NavPath from "@site/src/components/NavPath";
Frigate can send one anonymous usage report a day. The reports show the maintainers which hardware to support, which features people use, and how releases perform. Sharing is off until you turn it on.
## Turning it on
Enable **Share anonymous analytics** at <NavPath path="Settings > System > Telemetry" />, or set it in your config:
```yaml
telemetry:
analytics:true
```
The same page has a **Preview the report** button that shows exactly what the next report contains.
## How it's sent
- Once a day, as a JSON POST to `https://analytics.frigate.video/report`
- The server looks up your country and region from your IP address and never stores the address
- Raw reports are kept for 60 days; only aggregate totals are published
- A random install ID, stored in `/config/.analytics.json`, keeps your install from being counted twice. Turning sharing off deletes it
## What's never sent
- Camera, zone, group, profile, or user names
- Object labels, face names, or license plate text
- IP addresses, hostnames, URLs, or stream paths
- Credentials or API keys
- Events, recordings, or anything from them
## Every field
Fields marked public appear in the published totals. The machine-readable schema is [frigate-analytics-schema.json](pathname:///frigate-analytics-schema.json).
This section sets environment variables in the Frigate process for those unable to modify the environment of the container, like within Home Assistant OS. It's meant for process settings such as `LIBVA_DRIVER_NAME` or the TensorFlow thread counts below. Docker users should set environment variables in their `docker run` command (`-e LIBVA_DRIVER_NAME=i965`) or `docker-compose.yml` file (`environment:` section) instead. Values set here are stored in plain text in your config file, so credentials belong in `secrets.yaml`, Docker environment variables, or Docker secrets instead.
Names prefixed with`FRIGATE_`set here also take part in `{FRIGATE_VARIABLE_NAME}` substitution (see [below](#substitution-sources-and-precedence)), but `secrets.yaml` is the better home for them.
Besides`FRIGATE_`names, only these are accepted, and a variable already set in the container environment keeps its container value:
-`LIBVA_DRIVER_NAME` and `HSA_OVERRIDE_GFX_VERSION`
-`TF_INTRA_OP_PARALLELISM_THREADS`, `TF_INTER_OP_PARALLELISM_THREADS`, `TF_DATASET_THREAD_POOL_SIZE`, and `SHM_MAX_FRAMES`
-`USE_FP16`, `HF_HUB_OFFLINE`, and `TRANSFORMERS_OFFLINE`
-`HF_ENDPOINT`, `GITHUB_ENDPOINT`, `GITHUB_RAW_ENDPOINT`, and `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` (an `http://` or `https://` URL)
Any other name is ignored with a warning and must be set in the container environment.
Names prefixed with `FRIGATE_` set here take part in `{FRIGATE_VARIABLE_NAME}` substitution (see [below](#substitution-sources-and-precedence)), but `secrets.yaml` is the better home for them. Of these, only `FRIGATE_JWT_SECRET` is also set in the process environment.
<ConfigTabs>
<TabItem value="ui">
@@ -398,9 +407,9 @@ To do this:
2. Update the `ffmpeg.path` in your Frigate config to `/config/custom-ffmpeg`.
3. Restart Frigate and the custom version will be used if the steps above were done correctly.
Both binaries have to be executable by Frigate's unprivileged runtime user, so `chmod 755` them after extracting. The startup ownership sweep runs only once, so anything you add to `/config` later keeps whatever ownership and mode you gave it.
Both binaries have to be executable by Frigate's unprivileged runtime user, so `chmod 755` them after extracting. go2rtc runs as its own user, so the build must be world-executable for go2rtc to use it (`ffmpeg:` sources, the birdseye restream and transcoded live streams). The startup ownership sweep runs only once, so anything you add to `/config` later keeps whatever ownership and mode you gave it.
There is one exception, and it only affects [`FRIGATE_ROOT_SERVICES`](/configuration/non_root#keeping-individual-services-root) listing `frigate`. That mode runs Frigate as root while still handing `/config` to the unprivileged runtime user, so anything running as that user could swap the binary and gain root. A build inside any of Frigate's writable volumes (`/config`, `/media/frigate`, the cache and shm dirs) is ignored there and the bundled one is used, with a warning in the log. Keep the build somewhere root-owned (any absolute `ffmpeg.path` works, so a read-only bind mount such as `/opt/custom-ffmpeg` is enough) if you need both. The default mode and `FRIGATE_RUN_AS_ROOT=true` are unaffected and behave exactly as they always have.
There is one exception, and it only affects [`FRIGATE_ROOT_SERVICES`](/configuration/non_root#keeping-individual-services-root) listing `frigate` or `go2rtc`. That mode runs the listed service as root while still handing `/config` to the unprivileged runtime user, so anything running as that user could swap the binary and gain root. A build inside any of Frigate's writable volumes (`/config`, `/media/frigate`, the cache and shm dirs) is ignored by the root service, which uses the bundled one and logs a warning. A service that is not listed keeps using the custom build. Keep the build somewhere root-owned (any absolute `ffmpeg.path` works, so a read-only bind mount such as `/opt/custom-ffmpeg` is enough) if you need both. The default mode and `FRIGATE_RUN_AS_ROOT=true` are unaffected and behave exactly as they always have.
@@ -28,7 +28,7 @@ Many cheaper or older PTZs may not support this standard. Frigate will report an
The FeatureList on the [ONVIF Conformant Products Database](https://www.onvif.org/conformant-products/) can provide a starting point to determine a camera's compatibility with Frigate's autotracking. Look to see if a camera lists `PTZRelative`, `PTZRelativePanTilt` and/or `PTZRelativeZoom`. These features are required for autotracking, but some cameras still fail to respond even if they claim support.
A growing list of cameras and brands that have been reported by users to work with Frigate's autotracking can be found [here](cameras.md).
The [CCTV Camera Database](https://www.cctv-database.com/) is useful for researching a specific model.
## Configuration
@@ -192,7 +192,7 @@ In security and surveillance, it's common to use "spotter" cameras in combinatio
<FaqItem id="which-ptz-camera-should-i-use-for-autotracking" question="Which PTZ camera should I use for autotracking?">
See the community-maintained list of [ONVIF PTZ camera recommendations](cameras.md#onvif-ptz-camera-recommendations) for cameras and brands reported to work (and not work) with autotracking. This is not an exhaustive list that is frequently updated, so other cameras not listed may also work well. Frigate's autotracking was developed with a Dahua SD1A404XB-GNR (now sold as the EmpireTech PTZ1A4M-4X-S2), and Dahua / EmpireTech PTZs are the most consistently reported as working well.
See [ONVIF PTZ camera recommendations](cameras.md#onvif-ptz-camera-recommendations) for how to check a camera's autotracking support before buying. Frigate's autotracking was developed with a Dahua SD1A404XB-GNR (now sold as the EmpireTech PTZ1A4M-4X-S2), and Dahua / EmpireTech PTZs are the most consistently reported as working well.
When comparing models:
@@ -209,7 +209,7 @@ No. Reolink cameras (including the TrackMix series) lack the ONVIF FOV RelativeM
<FaqItem id="im-seeing-an-error-in-the-logs-that-my-camera-is-still-in-onvif-moving-status-what-does-this-mean" question={"I'm seeing an error in the logs that my camera \"is still in ONVIF 'MOVING' status.\" What does this mean?"}>
There are two possible known reasons for this (and perhaps others yet unknown): a slow PTZ motor or buggy camera firmware. Frigate uses an ONVIF parameter provided by the camera, `MoveStatus`, to determine when the PTZ's motor is moving or idle. According to some users, Hikvision PTZs (even with the latest firmware), are not updating this value after PTZ movement. Unfortunately there is no workaround to this bug in Hikvision firmware, so autotracking will not function correctly and should be disabled in your config. This may also be the case with other non-Hikvision cameras utilizing Hikvision firmware, such as some Annke models. In rare cases the vendor may provide fixed firmware on request; for example, Annke has supplied firmware that resolves this for the CZ504 (see the [camera recommendations list](cameras.md#onvif-ptz-camera-recommendations)).
There are two possible known reasons for this (and perhaps others yet unknown): a slow PTZ motor or buggy camera firmware. Frigate uses an ONVIF parameter provided by the camera, `MoveStatus`, to determine when the PTZ's motor is moving or idle. According to some users, Hikvision PTZs (even with the latest firmware), are not updating this value after PTZ movement. Unfortunately there is no workaround to this bug in Hikvision firmware, so autotracking will not function correctly and should be disabled in your config. This may also be the case with other non-Hikvision cameras utilizing Hikvision firmware, such as some Annke models.
@@ -225,36 +225,9 @@ An ONVIF-capable camera that supports relative movement within the field of view
## ONVIF PTZ camera recommendations
This list of working and non-working PTZ cameras is based on user feedback. If you'd like to report specific quirks or issues with a manufacturer or camera that would be helpful for other users, open a pull request to add to this list.
Before buying a PTZ camera, check its ONVIF support. The [ONVIF Conformant Products Database](https://www.onvif.org/conformant-products/) is the most reliable source. Look at a camera's FeatureList for `PTZRelative`, `PTZRelativePanTilt` and/or `PTZRelativeZoom`. Autotracking requires these features. If they are missing, autotracking will not work, though basic PTZ in the WebUI might. Some cameras still fail to respond even when they claim support. Avoid cameras with no database entry.
The FeatureList on the [ONVIF Conformant Products Database](https://www.onvif.org/conformant-products/) can provide a starting point to determine a camera's compatibility with Frigate's autotracking. Look to see if a camera lists `PTZRelative`, `PTZRelativePanTilt` and/or `PTZRelativeZoom`. These features are required for autotracking, but some cameras still fail to respond even if they claim support. If they are missing, autotracking will not work (though basic PTZ in the WebUI might). Avoid cameras with no database entry unless they are confirmed as working below.
| Brand or specific camera | PTZ Controls | Autotracking | Notes |
| Amcrest IP4M-S2112EW-AI | ✅ | ❌ | FOV relative movement not supported. |
| Amcrest IP5M-1190EW | ✅ | ❌ | ONVIF Port: 80. FOV relative movement not supported. |
| Annke CZ504 | ✅ | ❌ | |
| Axis Q-6155E | ✅ | ❌ | ONVIF service port: 80; Camera does not support MoveStatus. |
| Ctronics PTZ | ✅ | ❌ | |
| Dahua | ✅ | ✅ | Some low-end Dahuas (lite series, picoo series (commonly), among others) have been reported to not support autotracking. These models usually don't have a four digit model number with chassis prefix and options postfix (e.g. DH-P5AE-PV vs DH-SD49825GB-HNR). |
| Dahua DH-SD2A500HB | ✅ | ❌ | |
| Dahua DH-SD49825GB-HNR | ✅ | ✅ | |
| Dahua DH-P5AE-PV | ❌ | ❌ | |
| Foscam | ✅ | ❌ | In general support PTZ, but not relative move. There are no official ONVIF certifications and tests available on the ONVIF Conformant Products Database |
| Foscam R5 | ✅ | ❌ | |
| Foscam SD4 | ✅ | ❌ | |
| Hanwha XNP-6550RH | ✅ | ❌ | |
| Hikvision | ✅ | ❌ | Incomplete ONVIF support (MoveStatus won't update even on latest firmware) - reported with HWP-N4215IH-DE and DS-2DE3304W-DE, but likely others |
| Hikvision DS-2DE3A404IWG-E/W | ✅ | ✅ | |
| Reolink | ✅ | ❌ | |
| Speco O8P32X | ✅ | ❌ | |
| Sunba 405-D20X | ✅ | ❌ | Incomplete ONVIF support reported on original, and 4k models. All models are suspected incompatible. |
| Tapo | ✅ | ❌ | Many models supported, ONVIF Service Port: 2020 |
| Uniview IPC672LR-AX4DUPK | ✅ | ❌ | Firmware says FOV relative movement is supported, but camera doesn't actually move when sending ONVIF commands |
| Uniview IPC6612SR-X33-VG | ✅ | ✅ | Leave `calibrate_on_startup` as `False`. A user has reported that zooming with `absolute` is working. |
The [CCTV Camera Database](https://www.cctv-database.com/) is an open database of IP camera specifications and is useful for researching a specific model.
| `qwen3-vl` | `frames` | Strong visual and situational understanding, enhanced ability to identify smaller objects and interactions with object. Follows a sequence of frames on its own. |
| `qwen3.6`/`qwen3.8` | `frames` | Strong situational understanding, but missing DeepStack from qwen3-vl leading to worse performance for identifying objects in people's hand and other small details. |
| `gemma4` | `annotated_frames` | Strong situational understanding, sometimes resorts to more vague terms like 'interacts' instead of assigning a specific action. Loses track of activity that repeats or reverses, so it benefits from annotated frames. |
| `qwen3-vl` | `frames` | `natural` | Strong visual and situational understanding, enhanced ability to identify smaller objects and interactions with object. Follows a sequence of frames on its own. |
| `qwen3.6`/`qwen3.8` | `frames` | `natural` | Strong situational understanding, but missing DeepStack from qwen3-vl leading to worse performance for identifying objects in people's hand and other small details. |
| `gemma4` | `annotated_frames` | `default` | Strong situational understanding, sometimes resorts to more vague terms like 'interacts' instead of assigning a specific action. Loses track of activity that repeats or reverses, so it benefits from annotated frames. |
| `lfm3-vl` | `annotated_frames` | `concise` | Very efficient with fast inference, making it a good choice for less powerful hardware or high volumes of review items. |
#### Embedding models
@@ -95,7 +96,7 @@ The `embeddings` role needs a different kind of model. Text queries are matched
The `transcribe` role needs a model that accepts audio input. A text-only or vision-only model cannot serve this role. The following are recommended for local deployment of the `transcribe` role:
| `qwen3-asr` | Dedicated speech recognition model covering 30 languages, and the better choice for transcription quality. It only transcribes, so it cannot be shared with the `descriptions` or `chat` roles. |
| `gemma4` | General multimodal model that accepts audio as well as images, so one served model can cover `transcribe` alongside the other roles. Transcript quality is below `qwen3-asr`, particularly on noisy audio. |
@@ -343,7 +344,7 @@ To start using Gemini, you must first get an API key from [Google AI Studio](htt
- Set **API key** to your Gemini API key (or use an environment variable such as `{FRIGATE_GEMINI_API_KEY}`)
- Set **Model** to the desired model (e.g., `gemini-2.5-flash`)
- Set **Model** to the desired model (e.g., `gemini-3.5-flash-lite`)
</TabItem>
<TabItem value="yaml">
@@ -353,12 +354,18 @@ genai:
my_provider:
provider:gemini
api_key:"{FRIGATE_GEMINI_API_KEY}"
model:gemini-2.5-flash
model:gemini-3.5-flash-lite
```
</TabItem>
</ConfigTabs>
:::tip
Gemini 3.x models charge a (roughly) flat ~1,100 tokens per image regardless of resolution, so a 180p preview frame costs the same as a 480p recording frame. Set the review [image source](/configuration/genai/genai_review#image-source) to `recordings` to send higher quality frames at no extra cost, as long as recordings are enabled for the camera.
:::
:::note
To use a different Gemini-compatible API endpoint, set the `provider_options` with the `base_url` key to your provider's API URL. For example:
@@ -392,7 +392,12 @@ When your browser runs into problems playing back your camera streams, it will l
- **stalled**
- What it means: Playback has stalled because the player has fallen too far behind live (extended buffering or no data arriving).
- What to try: This is usually indicative of the browser struggling to decode too many high-resolution streams at once. Try selecting a lower-bandwidth stream (substream), reduce the number of live streams open, improve the network connection, or lower the camera resolution. Also check your camera's keyframe (I-frame) interval: shorter intervals make playback start and recover faster. You can also try increasing the timeout value in <NavPath path="Settings > UI" /> .
- What to try:
- This is usually indicative of the browser struggling to decode too many high-resolution streams at once.
- Try selecting a lower-bandwidth stream (substream), reduce the number of live streams open, improve the network connection, or lower the camera resolution.
- Also check your camera's keyframe (I-frame) interval: shorter intervals make playback start and recover faster.
- You can also try increasing the timeout value in <NavPath path="Settings > UI" /> .
- Also ensure your browser doesn't have JavaScript V8 optimizations disabled ("JavaScript optimisation and security" setting in Chrome-based browsers).
- Possible console messages from the player code:
- `Buffer time (10 seconds) exceeded, browser may not be playing media correctly.`
[INFO] fix-ownership: finished /media/frigate in 12m 4s
```
The scan has no percentage because the total isn't known until it finishes. Watch the boot sweep with `docker logs -f frigate`.
The scan has no percentage because the total isn't known until it finishes, so it reports a running count every 30 seconds instead. Watch the boot sweep with `docker logs -f frigate`.
Once the volumes are aligned, start Frigate normally. A file at `/config/.permissions_version` records what was done, so later boots skip the sweep unless you change `PUID`/`PGID`.
@@ -43,7 +43,7 @@ Notifications will be prevented if either:
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Notifications > Notifications" />.
1. Navigate to <NavPath path="Settings > Notifications" />.
- Set **Email** to your email address
- Enable notifications for the desired cameras
@@ -108,6 +108,29 @@ Currently, only Chrome supports images in notifications. Safari and Firefox will
Different platforms handle notifications differently, some settings changes may be required to get optimal notification delivery.
### Notification TTL
By default, Frigate sends notifications for an active alert with a `ttl` of `immediate`, so the push service either delivers them immediately or drops them. If your device is briefly unreachable (asleep, switching from Wi-Fi to cellular, or on a weak signal), those notifications are lost and you only receive the notification sent when the alert ends, which is always kept for up to an hour.
Setting `ttl` to `reliable` tells the push service to keep retrying these notifications for up to 30 seconds. This makes delivery more reliable, but a notification delivered late will still say an object is detected, even if the object has already left.
<ConfigTabs>
<TabItem value="ui">
1. Navigate to <NavPath path="Settings > Notifications" />.
- Expand **Advanced Settings** and set **Notification TTL** to **Reliable**
</TabItem>
<TabItem value="yaml">
```yaml
notifications:
ttl:reliable# retry an undelivered notification for up to 30 seconds
```
</TabItem>
</ConfigTabs>
### Android
Most Android phones have battery optimization settings. To get reliable Notification delivery the browser (Chrome, Firefox) should have battery optimizations disabled. If Frigate is running as a PWA then the Frigate app should have battery optimizations disabled as well.
@@ -151,7 +151,7 @@ Along with picking a detector for your hardware, you will choose a model's **inp
:::tip
The best detection accuracy comes from a model trained on images that look like what Frigate actually sees: security camera footage cropped to regions of interest. You can train or fine-tune your own model on images like this and run it as a custom model (see the per-detector sections below), but [Frigate+](/plus) makes this much easier by handling the training for you on images submitted from your own cameras. For YOLOv9, the `s` (small) variant at `320x320` resolution is a good place to start.
The best detection accuracy comes from a model trained on images that look like what Frigate actually sees: security camera footage cropped to regions of interest. You can train or fine-tune your own model on images like this and run it as a custom model (see the per-detector sections below), but [Frigate+](/plus) makes this much easier by handling the training for you on images submitted from your own cameras. For YOLOv9, the `s` (small) variant at `320x320` resolution is a good place to start, and the larger `c` variant is available for more powerful hardware.
:::
@@ -361,7 +361,7 @@ The NPU firmware is loaded by the host kernel and is not part of the Frigate ima
Frigate bundles a specific version of Intel's [linux-npu-driver](https://github.com/intel/linux-npu-driver/releases), and the host firmware must come from that release or a newer one. Firmware older than the bundled driver may fail with `MAPPED_INFERENCE_VERSION is NOT compatible with the ELF`, where `Expected` is the version the firmware supports and `received` is the version the bundled compiler produced. Distributions often package older firmware than the driver Frigate ships, so check the build date on the host with `sudo dmesg | grep -i vpu` and update it there if needed.
Intel NPUs cannot be used under Home Assistant OS, which does not include the NPU firmware.
Intel NPUs can be used under Home Assistant OS 18.4 or newer.
@@ -413,17 +413,18 @@ Avoid removing audio from only one of the two streams (for example with `-an`).
As a general rule, features that read recordings prefer the main stream and fall back to the sub stream for time ranges where the main recordings have expired. Analytics features use only the main stream.
| Recording playback (History and Review) | Both (main preferred with sub fallback by default), or exactly one stream when a quality is selected manually |
| Tracking details and Explore clip playback | Main, falling back to sub where the main recordings have expired |
| Recording playback (History and Review) | Both (main preferred with sub fallback by default), or exactly one stream when a quality is selected manually |
| Tracking details and Explore clip playback | Main, falling back to sub where the main recordings have expired |
| Exports | Both (main preferred with sub fallback by default), or exactly one stream when a quality is selected in the export dialog |
| Clip downloads | Main; sub is used when no main recordings remain in the range (streams are never mixed in one file) |
| Frames grabbed from a recording in History (download snapshot, submit frame to Frigate+) | Main preferred, sub fallback |
| Audio extraction (e.g., transcription) | Main preferred, sub fallback |
| Motion search | Main only |
| Review timeline motion data | Main only |
| Storage usage statistics | Both streams counted, and listed separately per camera |
| Clip downloads | Main; sub is used when no main recordings remain in the range (streams are never mixed in one file) |
| Debug replay | Main; sub is used when no main recordings remain in the range (streams are never mixed in one file) |
| Frames grabbed from a recording in History (download snapshot, submit frame to Frigate+) | Main preferred, sub fallback |
| Audio extraction (e.g., transcription) | Main preferred, sub fallback |
| Motion search | Main only |
| Review timeline motion data | Main only |
| Storage usage statistics | Both streams counted, and listed separately per camera |
This table covers only features that read recordings from disk. Tracked object snapshots and thumbnails (the images shown in Explore and sent with notifications, and the images submitted to Frigate+ from a tracked object) are captured live from the `detect` stream as the object is tracked, never from recordings, so sub stream recording does not affect them.
@@ -221,6 +221,8 @@ Any `#` parameter on a bare `rtsp://` source disables the backchannel unless the
For security reasons, the `echo:`, `expr:`, and `exec:` stream sources are disabled by default in go2rtc. These sources allow arbitrary command execution and can pose security risks if misconfigured.
go2rtc's `${VAR:default}` variable syntax is also disabled by default in stream sources, since its default can name one of those sources. Use Frigate's [`{FRIGATE_*}` substitution](./config.md#environment-variable-substitution) instead.
If you attempt to use these sources in your configuration, the streams will be removed and an error message will be printed in the logs.
To enable these sources, you must set the environment variable `GO2RTC_ALLOW_ARBITRARY_EXEC=true`. This can be done in your Docker Compose file or container environment, or for Home Assistant App users with the `go2rtc_allow_arbitrary_exec` option in the App's configuration. The `environment_vars` section of the Frigate config can't enable it:
@@ -94,7 +94,7 @@ After closing VS Code, you may still have containers running. To close everythin
GitHub will execute unit tests on new PRs. You must ensure that all tests pass.
```shell
python3 -u -m unittest
python3 -u -m frigate.test
```
#### FFMPEG Hardware Acceleration
@@ -207,7 +207,7 @@ npm run lint
- Ensure the backend [unit tests](#unit-tests) pass. Your PR cannot be merged unless tests pass.
```shell
python3 -u -m unittest
python3 -u -m frigate.test
```
- Ensure the end-to-end tests pass. They run in Playwright against a production build with mocked API data, so they don't need a running Frigate instance. Add or update tests in `web/e2e/specs/` when you change UI behavior.
@@ -763,20 +763,17 @@ The community supported docker image tags for the current stable version are:
:::warning
As of Home Assistant Operating System 10.2 and Home Assistant 2023.6 defining separate network storage for media is supported.
There are important limitations in HA OS to be aware of:
- Separate local storage for media is not yet supported by Home Assistant
- AMD GPUs are not supported because HA OS does not include the mesa driver.
- Intel NPUs are not supported because HA OS does not include the NPU firmware.
- Intel NPUs require Home Assistant OS 18.4 or newer. Earlier releases do not include the NPU firmware.
- Nvidia GPUs are not supported because HA Apps do not support the Nvidia runtime.
:::
:::tip
See [the network storage guide](/guides/ha_network_storage.md) for instructions to setup network storage for frigate.
Frigate's media can be kept on separate storage, either a network share (Home Assistant 2023.6 or newer) or a local disk such as a second internal drive or a USB drive (Home Assistant 2026.11 or newer). See [the storage guide](/guides/ha_network_storage.md) for setup instructions.
If [anonymous analytics](/configuration/advanced/analytics) sharing is turned on, Frigate sends one report a day to `https://analytics.frigate.video`. It's off by default, so no outbound connection happens unless you enable it:
```yaml
telemetry:
analytics:true
```
### Push Notifications
When [notifications](/configuration/notifications) are enabled and users have registered for push notifications in the web UI, Frigate sends push messages through the browser vendor's push service (e.g., Google FCM, Mozilla autopush). This requires internet access from the Frigate server to these push endpoints.
@@ -171,7 +180,7 @@ To run Frigate in an air-gapped or offline environment:
2.**Pre-download the training base weights**: If you plan to train custom classification models, set `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` before training, then run one training job while online. Without this variable the base weights are cached outside `/config/` and are lost whenever the container is recreated, so a later training run will fail offline. If the machine never has internet access, copy the weights in manually as described below.
3.**Disable version check**: Set `telemetry.version_check: false` in your configuration.
4.**Block outbound model requests**: Set the `HF_HUB_OFFLINE=1` and `TRANSFORMERS_OFFLINE=1` environment variables to prevent HuggingFace and Transformers from attempting any network requests.
5.**Avoid cloud features**: Do not configure Frigate+, Generative AI providers that require internet, or cloud MQTT brokers.
5.**Avoid cloud features**: Do not configure Frigate+, Generative AI providers that require internet, or cloud MQTT brokers, and leave anonymous analytics off (its default).
6.**Use local model mirrors**: If limited internet is available, set the `HF_ENDPOINT`, `GITHUB_ENDPOINT`, `GITHUB_RAW_ENDPOINT`, and `TF_KERAS_MOBILENET_V2_WEIGHTS_URL` environment variables to point to local mirrors.
After these steps, Frigate will operate with no outbound internet connections.
As of Home Assistant 2023.6, Network Mounted Storage is supported for Apps.
Frigate's media (`/media/frigate`) can be stored on a network share or a separate local disk (internal or USB) instead of the Home Assistant system disk.
## Setting Up Remote Storage For Frigate
## Prerequisites
### Prerequisites
### Network storage
- Home Assistant 2023.6 or newer is installed
- Running Home Assistant Operating System 10.2 or newer OR Running Supervised with latest os-agent installed (this is required for supervised install)
### Local disk
- Home Assistant 2026.11 or newer is installed
- The disk is already formatted, ideally as ext4 (Home Assistant does not format disks). Avoid FAT32, exFAT, and NTFS, which do not support Linux file permissions.
## Setting Up Storage For Frigate
### Initial Setup
1. Stop the Frigate App
### Move current data
Keeping the current data is optional, but the data will need to be moved regardless so the share can be created successfully.
Keeping the current data is optional, but `/media/frigate` must be moved or deleted so Home Assistant can mount the storage there. The database and config are stored elsewhere and are not affected.
#### If you want to keep the current data
1.Move the frigate.db, frigate.db-shm, frigate.db-wal files to the /config directory
2. Rename the /media/frigate folder to /media/frigate_tmp
1.Rename the /media/frigate folder to /media/frigate_tmp
#### If you don't want to keep the current data
1. Delete the /media/frigate folder and all of its contents
### Create the media share
### Add the storage
1. Go to **Settings -> System -> Storage -> Add Network Storage**
2. Name the share `frigate` (this is required)
3. Choose type `media`
4.Fill out the additional required info for your particular NAS
1. Go to **Settings -> System -> Storage -> Add storage**
2. Name the storage `frigate` (this is required)
3. Choose usage `media`
4.Choose the type:
- For network storage, choose `Samba/Windows (CIFS)` or `Network File System (NFS)` and fill out the additional required info for your particular NAS
- For a local disk, choose `Local disk` and select the disk to use
5. Connect
6. Move files from `/media/frigate_tmp` to `/media/frigate` if they were kept in previous step
@@ -47,6 +47,10 @@ This is a fork (with fixed errors and new features) of [original Double Take](ht
[Frigate telegram](https://github.com/OldTyT/frigate-telegram) makes it possible to send events from Frigate to Telegram. Events are sent as a message with a text description, video, and thumbnail.
[FrigatePiP](https://github.com/maciejgornicz/frigate-pip) pops up a small picture-in-picture window with a camera's live video in a corner of the screen when Frigate detects an object, and closes it when the activity ends. It runs as a Windows tray app and on Linux (desktop windows, a console framebuffer, a terminal or tmux popups), receives events over Frigate's WebSocket or MQTT and plays the go2rtc RTSP stream with hardware decoding and camera audio.
[kiosk-monitor](https://github.com/extremeshok/kiosk-monitor) is a Raspberry Pi watchdog that runs Chromium fullscreen on a Frigate dashboard (optionally with VLC on a second monitor for an RTSP camera stream), auto-restarts on frozen screens or unreachable URLs, and ships a Birdseye-aware Chromium helper that auto-sizes the grid to the display.
@@ -55,6 +59,10 @@ This is a fork (with fixed errors and new features) of [original Double Take](ht
[Periscope](https://github.com/maksz42/periscope) is a lightweight Android app that turns old devices into live viewers for Frigate. It works on Android 2.2 and above, including Android TV. It supports authentication and HTTPS.
[reostream](https://github.com/VoltTech21/reostream) is a proxy for Reolink cameras that pulls video over Reolink's own protocol (the one the Reolink app and NVR use) instead of the camera's RTSP server, and serves it back as RTSP for go2rtc and Frigate. It helps models whose RTSP stream smears, drops frames or loses full resolution, and supports two-way talk.
[Scrypted - Frigate bridge](https://github.com/apocaliss92/scrypted-frigate-bridge) is a plugin that allows you to ingest Frigate detections, motion, videoclips on Scrypted as well as provide templates to export rebroadcast configurations on Frigate.
@@ -25,6 +25,12 @@ If you have an active Frigate+ subscription, new uploads will be scanned for the
Suggestions are converted to labels when saving, so you should remove any errant suggestions. There is already some logic designed to avoid duplicate labels, but you may still occasionally see some duplicate suggestions. You should keep the most accurate bounding box and delete any duplicates so that you have just one label per object remaining.
## Reviewing annotations with Patches
The Patches tab on the Images page shows a cropped view of every annotation for a label in a grid. Scanning the crops makes it much easier to spot a mislabeled object than paging through full images one at a time. Pick a label to get started, and optionally narrow the results to a single camera. Clicking a patch opens that image in the editor so you can fix the annotation.
Patches only include annotations from images you have already verified.
## False positive labels
False positives will be shown with a red box and the label will have a strike through. These can't be adjusted, but they can be deleted if you accidentally submit a true positive as a false positive from Frigate.
@@ -51,3 +57,12 @@ Misidentified objects should have a correct label added. For example, if a perso
| `scrollwheel` | Zoom in/out |
| `f` | Hide/show all but current box |
| `spacebar` | Verify and save |
## Deleting images
In most cases, you should keep your existing images. Removing training data usually makes accuracy worse, not better, so you shouldn't delete images just because you think you made some annotation mistakes. Deleting images makes sense when you move to a new location, or significantly upgrade or reposition your cameras.
- To delete all images for a camera, use the **Delete Images** button for that camera on the Cameras page.
- To delete all images in your account, use **Delete All Images** on the Settings page.
Deletions run in the background, and their progress is shown in the bulk operations panel. Deleted images cannot be recovered and are no longer used to train your models.
@@ -26,7 +26,9 @@ Yes. Subscriptions to Frigate+ provide access to the infrastructure used to trai
### Can I use Frigate+ models commercially?
A standard subscription covers use on camera systems you own or operate, including for your business. A shop, restaurant, warehouse, or office running Frigate+ at its own locations (including multiple locations) is exactly the kind of use the subscription is for.
What the standard subscription does not cover is using Frigate+ models to provide a product or service to others. If you're deploying models at your customers' sites, bundling them with hardware you sell, or running them as part of a hosted or managed service, even if your customers never receive the model files themselves, you'll need a commercial license.
Note that professional installers are fine under standard subscriptions when each customer holds their own Frigate+ subscription. The commercial license is for cases where your license powers your customers' sites.
@@ -17,7 +17,7 @@ For more detailed recommendations, you can refer to the docs on [annotating](./a
## Step 2: Submit a model request
Once you have an initial set of verified images, you can request a model on the Models page. For guidance on choosing a model type, refer to [this part of the documentation](./index.md#available-model-types). If you are unsure which type to request, you can test the base model for each version from the "Base Models" tab. Each model request requires 1 of the 12 trainings that you receive with your annual subscription. This model will support all [label types available](./index.md#available-label-types) even if you do not submit any examples for those labels. Model creation can take up to 36 hours.
Once you have an initial set of verified images, you can request a model on the Models page. For guidance on choosing a model type, refer to [this part of the documentation](./index.md#available-model-types). If you are unsure which type to request, you can test the base model for each version from the "Base Models" tab. For most hardware, `yolov9` is recommended; `mobiledet` is a legacy model type and will be removed in 2027. Each model request requires 1 of the 12 trainings that you receive with your annual subscription. This model will support all [label types available](./index.md#available-label-types) even if you do not submit any examples for those labels. Model creation can take up to 36 hours.
<a href="https://frigate.video/plus" target="_blank" rel="nofollow">Frigate+</a> offers models trained on images submitted by Frigate+ users from their security cameras and is specifically designed for the way Frigate NVR analyzes video footage. These models offer higher accuracy with less resources. The images you upload are used to fine tune a base model trained from images uploaded by all Frigate+ users. This fine tuning process results in a model that is optimized for accuracy in your specific conditions.
With a subscription, 12 model trainings to fine tune your model per year are included. In addition, you will have access to any base models published while your subscription is active. If you cancel your subscription, you will retain access to any trained and base models in your account. An active subscription is required to submit model requests or purchase additional trainings. New base models are published quarterly with target dates of January 15th, April 15th, July 15th, and October 15th.
With a subscription, 12 model trainings to fine tune your model per year are included. In addition, you will have access to any base models published while your subscription is active. If you cancel your subscription, you will retain access to any trained and base models in your account. An active subscription is required to submit model requests or purchase additional trainings. New base models are published twice per year.
Information on how to integrate Frigate+ with Frigate can be found in the [integration docs](../integrations/plus.md).
## Available model types
There are three model types offered in Frigate+, `mobiledet`, `yolonas`, and `yolov9`. All of these models are object detection models and are trained to detect the same set of labels [listed below](#available-label-types).
There are three model types offered in Frigate+, `yolov9`, `yolonas`, and `mobiledet` (legacy). All of these models are object detection models and are trained to detect the same set of labels [listed below](#available-label-types).
Not all model types are supported by all detectors, so it's important to choose a model type to match your detector as shown in the table under [supported detector types](#supported-detector-types). You can test model types for compatibility and speed on your hardware by using the base models.
| `mobiledet` | Based on the same architecture as the default model included with Frigate. Runs on Google Coral devices and CPUs. |
| `yolonas` | A newer architecture that offers slightly higher accuracy and improved detection of small objects. Runs on Intel, NVidia GPUs, and AMD GPUs. |
| `yolov9` | A leading SOTA (state of the art) object detection model with similar performance to yolonas, but on a wider range of hardware options. Runs on most hardware. |
| `yolonas` | A newer architecture that offers slightly higher accuracy and improved detection of small objects. Runs on Intel, NVidia GPUs, and AMD GPUs. |
| `mobiledet` | Legacy. Based on the same architecture as the default model included with Frigate. Runs on Google Coral devices and CPUs. |
:::warning
`mobiledet` is a legacy model type. Base model 2026.3 is the last base model update for `mobiledet`, and it is planned to be removed from Frigate+ in 2027. If you are using `mobiledet` with a Google Coral, request a `yolov9` model with the `edgetpu` variant instead.
:::
### YOLOv9 Details
YOLOv9 models are available in `s`, `t`, `edgetpu` variants. When requesting a `yolov9` model, you will be prompted to choose a variant. If you want the model to be compatible with a Google Coral, you will need to choose the `edgetpu` variant. If you are unsure what variant to choose, you should perform some tests with the base models to find the performance level that suits you. The `s` size is most similar to the current `yolonas` models in terms of inference times and accuracy, and a good place to start is the `320x320` resolution model for `yolov9s`.
YOLOv9 models are available in `t`, `s`, `c`, and`edgetpu` variants, and an `m` size is coming soon. When requesting a `yolov9` model, you will be prompted to choose a variant. If you want the model to be compatible with a Google Coral, you will need to choose the `edgetpu` variant, which requires Frigate 0.17 or later. If you are unsure what variant to choose, you should perform some tests with the base models to find the performance level that suits you. The `s` size is most similar to the current `yolonas` models in terms of inference times and accuracy, and a good place to start is the `320x320` resolution model for `yolov9s`. The `c` size is larger and offers higher accuracy at the cost of slower inference, so it is best suited to more powerful hardware such as GPUs.
| Variant | Size | Parameters | Speed and accuracy | Best suited for |
| `t` | Tiny | ~2.0M | Fastest inference, lowest accuracy | Low power hardware or a large number of cameras |
| `s` | Small | ~7.1M | Balanced. Similar inference times and accuracy to `yolonas` | Most users. Start with `320x320` |
| `m` | Medium (coming soon) | ~20.0M | Slower than `s` with higher accuracy | Mid-range GPUs and NPUs |
| `c` | Compact | ~25.3M | Highest accuracy, slowest inference | More powerful hardware such as GPUs |
| `edgetpu` | N/A | N/A | Optimized to run on the Coral's Edge TPU | Google Coral devices only (requires Frigate 0.17+) |
Parameter counts are for the standard YOLOv9 architectures. Actual inference times depend on your hardware and the input resolution you choose, so test with the base models before requesting a model.
:::info
@@ -33,7 +49,7 @@ When switching to YOLOv9, you may need to adjust your thresholds for some object
#### Hailo Support
If you have a Hailo device, you will need to specify the hardware you have when submitting a model request because they are not cross compatible. Please test using the available base models before submitting your model request.
If you have a Hailo device, you will need to specify the hardware you have when submitting a model request because they are not cross compatible. Hailo models are available for the `t`, `s`, and `c` variants on Hailo8, Hailo8L, and Hailo8R devices. Please test using the available base models before submitting your model request.
#### Rockchip (RKNN) Support
@@ -43,15 +59,15 @@ Rockchip models are automatically converted as of 0.17. For 0.16, YOLOv9 onnx mo
Currently, Frigate+ models support CPU (`cpu`), Google Coral (`edgetpu`), OpenVino (`openvino`), ONNX (`onnx`), Hailo (`hailo`), and Rockchip (`rknn`) detectors.
| Hardware | Recommended Detector Type | Recommended Model Type |
@@ -66,7 +82,7 @@ Some users may find that Frigate+ models result in more false positives initiall
Frigate+ models support a more relevant set of objects for security cameras. The labels for annotation in Frigate+ are configurable by editing the camera in the Cameras section of Frigate+. Currently, the following objects are supported:
@@ -170,7 +170,7 @@ Open one of the tracked objects in Explore → **Tracking Details**. If the dete
What helps:
- **Improve the view**: even a small angle change that gets more of the car visible could lift scores enough to stabilize tracking.
- **Use a more accurate model**: switching from `mobiledet` to `yolov9`, or stepping up to a larger variant like `yolov9-s` over `yolov9-t`, can help (at the cost of inference time, and still on the COCO dataset). The biggest gains usually come from fine-tuning a model on images from your own cameras so it learns your specific scene. [Frigate+](https://frigate.video/plus) is a paid option that does this - models are trained on security-camera footage and can be fine-tuned on images you submit from your own setup.
- **Use a more accurate model**: switching from `mobiledet` to `yolov9`, or stepping up to a larger variant like `yolov9-s` over `yolov9-t` (or `yolov9-c` on more powerful hardware), can help (at the cost of inference time, and still on the COCO dataset). The biggest gains usually come from fine-tuning a model on images from your own cameras so it learns your specific scene. [Frigate+](https://frigate.video/plus) is a paid option that does this - models are trained on security-camera footage and can be fine-tuned on images you submit from your own setup.
- **Don't set `detect -> stationary -> max_frames` for `car`**: it artificially ends tracking and forces re-detection as a new object. See [Stationary Objects](../configuration/stationary_objects.md).
- **Restrict alerts to the areas you care about** with `required_zones`. See [Zones](../configuration/zones.md#restricting-alerts-and-detections-to-specific-zones). Make sure those zones use the default `loitering_time: 0` unless you specifically want the review item to stay open until the car leaves.
- **Filter impossible locations** with [object filter masks](../configuration/masks.md#object-filter-masks) if cars are being detected on rooftops, treetops, etc.
@@ -24,6 +37,11 @@ class NotificationConfig(FrigateBaseModel):
title="Cooldown period",
description="Cooldown (seconds) between notifications to avoid spamming recipients.",
)
ttl:NotificationTTLEnum=Field(
default=NotificationTTLEnum.immediate,
title="Notification TTL",
description="How the push service handles a notification sent while an alert is active if your device can't be reached. Immediate delivers it right away or drops it. Reliable keeps retrying for up to 30 seconds. The notification sent when an alert ends is always kept for up to an hour.",
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.