From 407817a3b1d73949a584d81826cafb415f04cd0d Mon Sep 17 00:00:00 2001
From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com>
Date: Sun, 31 May 2026 08:51:32 -0500
Subject: [PATCH] Motion search fixes (#23359)
* improve error parsing and increase skip default
* improve motion search layout to match tracking details
* implement draw and move mode on mobile
* update motion search docs
* language tweaks
* improve tips
* note actions menu
---
docs/docs/configuration/review.md | 20 ++++-
frigate/api/motion_search.py | 4 +-
web/public/locales/en/views/motionSearch.json | 4 +-
.../motion-search/MotionSearchDialog.tsx | 83 +++++++++++++++++--
.../motion-search/MotionSearchROICanvas.tsx | 6 +-
.../views/motion-search/MotionSearchView.tsx | 10 ++-
6 files changed, 115 insertions(+), 12 deletions(-)
diff --git a/docs/docs/configuration/review.md b/docs/docs/configuration/review.md
index 9f160c9487..00b18219ce 100644
--- a/docs/docs/configuration/review.md
+++ b/docs/docs/configuration/review.md
@@ -153,7 +153,7 @@ Clicking a preview clip seeks the recording player to that timestamp so you can
Motion Search lets you scan recorded footage for changes inside a region of interest you draw on the camera. Unlike Motion Previews, which surfaces what Frigate's motion detector flagged in real time, Motion Search re-analyzes the saved recordings, so it can find changes that were missed (for example, an object that appeared while motion detection was paused by `lightning_threshold`, or in a region that is normally motion-masked).
-To start a search, click the kebab menu on a camera in the page and choose **Motion Search**. In the dialog:
+To start a search, open the Actions menu in History or click the kebab menu on a camera in the page and choose **Motion Search**. In the dialog:
1. Pick the camera and time range to scan.
2. Draw a polygon on the camera frame to define the region of interest.
@@ -170,3 +170,21 @@ To start a search, click the kebab menu on a camera in the {
if (!selectedCamera) return undefined;
return config.cameras[selectedCamera];
}, [config, selectedCamera]);
+ const aspectRatio = useMemo(() => {
+ if (!cameraConfig) {
+ return 16 / 9;
+ }
+
+ return cameraConfig.detect.width / cameraConfig.detect.height;
+ }, [cameraConfig]);
+
+ // Determine camera aspect ratio category
+ const cameraAspect = useMemo(() => {
+ if (!aspectRatio) {
+ return "normal";
+ } else if (aspectRatio > ASPECT_WIDE_LAYOUT) {
+ return "wide";
+ } else if (aspectRatio < ASPECT_PORTRAIT_LAYOUT) {
+ return "tall";
+ } else {
+ return "normal";
+ }
+ }, [aspectRatio]);
+
const polygonClosed = useMemo(
() => !isDrawingROI && polygonPoints.length >= 3,
[isDrawingROI, polygonPoints.length],
@@ -144,6 +168,7 @@ export default function MotionSearchDialog({
useEffect(() => {
setImageLoaded(false);
+ setPanMode(false);
}, [selectedCamera]);
const Overlay = isDesktop ? Dialog : Drawer;
@@ -218,7 +243,13 @@ export default function MotionSearchDialog({
)}
-
+