How to Debug Frigate Detection Performance and Tune FPS: A Complete Guide
To debug Frigate detection performance, monitor the three core FPS metrics—camera_fps, process_fps, and detection_fps—via the /metrics endpoint, then adjust the detect.fps configuration value to match your hardware capabilities while watching for watchdog restarts.
Frigate's object detection pipeline operates as a tightly coupled three-stage system in the blakeblackshear/frigate repository. Understanding how FFmpeg capture, motion detection, and inference metrics interact is essential for identifying bottlenecks and safely tuning frame rates without triggering protective restarts.
Understanding Frigate's Three FPS Metrics
Frigate tracks distinct performance indicators at different pipeline stages. These values are stored in the CameraMetrics dataclass (frigate/camera/__init__.py) and exposed via Prometheus metrics and WebSocket status topics.
Camera FPS (camera_fps)
The camera FPS represents the raw frame rate pulled from your camera stream via FFmpeg. In frigate/video/ffmpeg.py, the capture_frames() function continuously updates this value using an EventsPerSecond tracker:
fps.value = frame_rate.eps()
You can find this logic at lines 89‑90 of frigate/video/ffmpeg.py. This metric reflects exactly what your camera is delivering, independent of downstream processing capacity.
Process FPS (process_fps)
The process FPS measures how quickly frames move from the capture queue into the detection pipeline. Updated in frigate/video/detect.py at lines 545‑546, this metric indicates whether your system is keeping up with the incoming stream or dropping frames due to queue saturation:
camera_metrics.process_fps.value = fps_tracker.eps()
If this value diverges significantly from camera_fps, your hardware cannot process frames fast enough.
Detection FPS (detection_fps)
The detection FPS tracks the actual inference output rate from your object detector (GPU or CPU). This is updated after each detection batch in frigate/video/detect.py at lines 555‑556:
camera_metrics.detection_fps.value = object_detector.fps.eps()
When detection_fps falls below process_fps, your inference hardware has become the bottleneck.
Stall Detection (stalls_last_hour)
The CameraWatchdog class monitors pipeline health by tracking stalls—moments when detection falls behind the expected frame interval. Populated in CameraWatchdog.run() at lines 48‑50 of frigate/video/ffmpeg.py, this counter increments when frames arrive but processing lags persistently.
How the Watchdog Monitors Detection Performance
Frigate implements protective logic in frigate/video/ffmpeg.py to prevent runaway resource consumption. The CameraWatchdog enforces an upper bound based on your configured detect.fps value (defined in frigate/config/camera.py).
The FPS Overflow Protection
If camera_fps exceeds detect.fps + 10 for three consecutive checks, the watchdog terminates the FFmpeg process and initiates a restart. This logic resides at lines 91‑99 of frigate/video/ffmpeg.py:
# Pseudocode representation of the watchdog logic
if camera_fps > (detect.fps + 10):
consecutive_exceedances += 1
if consecutive_exceedances >= 3:
restart_ffmpeg()
You will see "exceeded fps limit" messages in your logs when this triggers.
Queue Management and Skipped Frames
When the detection pipeline cannot keep up, Frigate drops frames rather than accumulating infinite backlog. In frigate/video/ffmpeg.py at lines 21‑23, queue-full conditions increment a skip counter:
except queue.Full:
skipped_eps.update()
These skipped frames reduce effective process_fps and appear in metrics as skipped_fps.
Step-by-Step Debugging Workflow
Follow this systematic approach to diagnose performance issues using the actual source code implementation.
-
Inspect Live Metrics
Query the Prometheus endpoint to establish baseline values:
curl http://localhost:5000/metrics | grep "frigate_.*_fps"Look for
frigate_camera_fps{camera="your_camera"},frigate_process_fps, andfrigate_detection_fps. -
Analyze Watchdog Logs
Search Frigate logs for protective restarts:
docker logs frigate | grep -E "(exceeded fps limit|No frames received|stall)"Messages like
front_door exceeded fps limit. Exiting ffmpeg...(generated at lines 998‑1000 offfmpeg.py) indicate configuration mismatches. -
Validate Queue Health
Compare
camera_fpsagainstprocess_fps. A significant gap indicates frame drops. Checkfrigate_skipped_fpsmetrics (line 90 inffmpeg.py) to confirm queue saturation. -
Measure Hardware Utilization
Run
nvidia-smifor GPU inference ortopfor CPU detection. If utilization hovers near 100% whiledetection_fpslags behindprocess_fps, your model requires more resources than available. -
Verify Stall Counts
Ensure
frigate_stalls_last_hourremains at zero. Persistent stalls indicate the motion detector or object detector cannot maintain real-time processing.
Tuning detect.fps for Optimal Performance
The detect.fps configuration value serves as the primary control knob for balancing detection accuracy against resource usage.
Configuration File Method
Edit your config.yml to set realistic targets based on your hardware capabilities:
cameras:
front_door:
detect:
fps: 12 # Increase from default 5 if GPU permits
enabled: True
After saving, reload configuration via the web UI or restart the Frigate container. The CameraConfig.detect.fps value is read by the ImprovedMotionDetector instantiation at lines 91‑95 of frigate/video/detect.py.
Runtime Adjustment via REST API
Modify FPS without service interruption using the configuration endpoint:
curl -X POST http://localhost:5000/api/config/cameras/front_door \
-H "Content-Type: application/json" \
-d '{"detect": {"fps": 15}}'
Frigate propagates this change through CameraConfigUpdateSubscriber, which the watchdog reads on its next loop iteration (see ffmpeg.py:78‑81).
Automating Performance Monitoring
Use this Python script to programmatically track the three critical metrics from the /metrics endpoint:
import requests
METRICS_URL = "http://localhost:5000/metrics"
def get_camera_fps_metrics(camera_name: str) -> dict:
"""Fetch FPS metrics for a specific camera from Frigate's Prometheus endpoint."""
resp = requests.get(METRICS_URL)
lines = resp.text.splitlines()
metrics = {}
for line in lines:
if f'camera="{camera_name}"' in line:
if line.startswith("frigate_camera_fps"):
metrics["camera_fps"] = float(line.split()[-1])
elif line.startswith("frigate_process_fps"):
metrics["process_fps"] = float(line.split()[-1])
elif line.startswith("frigate_detection_fps"):
metrics["detection_fps"] = float(line.split()[-1])
elif line.startswith("frigate_stalls_last_hour"):
metrics["stalls"] = int(float(line.split()[-1]))
return metrics
# Example usage
print(get_camera_fps_metrics("front_door"))
This queries the same metric names updated by capture_frames() in ffmpeg.py and process_frames() in detect.py.
Summary
- Three metrics matter:
camera_fps(input rate),process_fps(queue processing rate), anddetection_fps(inference output rate) tracked inCameraMetrics. - Watchdog protection: The system restarts FFmpeg if
camera_fpsexceedsdetect.fps + 10to prevent resource exhaustion. - Queue drops: When overwhelmed, Frigate skips frames (tracked in
skipped_fps) rather than falling infinite behind. - Tuning approach: Adjust
detect.fpsinconfig.ymlor via REST API, then validate through the/metricsendpoint and watchdog logs. - Key files: Monitor
frigate/video/ffmpeg.pyfor capture logic andfrigate/video/detect.pyfor detection pipeline performance.
Frequently Asked Questions
Why is my detection FPS lower than my camera FPS?
Your inference hardware (GPU or CPU) cannot process frames as fast as they arrive. When detection_fps drops significantly below camera_fps, the object detector has become the bottleneck. Check nvidia-smi or CPU utilization—if usage is near 100%, reduce detect.fps in your configuration or upgrade hardware.
What causes the "exceeded fps limit" error in Frigate logs?
This occurs when your camera stream delivers frames faster than detect.fps + 10 for three consecutive watchdog checks. The CameraWatchdog in frigate/video/ffmpeg.py (lines 91‑99) triggers an FFmpeg restart to protect system resources. Either increase detect.fps to match your camera's actual output or reduce the camera's stream framerate to prevent watchdog intervention.
How do I know if Frigate is dropping frames?
Compare camera_fps against process_fps and check skipped_fps metrics. If process_fps is significantly lower than camera_fps, frames are being discarded due to full queues. The skipped_eps.update() call at lines 21‑23 of frigate/video/ffmpeg.py tracks these drops, which you can monitor via the Prometheus frigate_skipped_fps metric.
Can I change detection FPS without restarting Frigate?
Yes, use the REST API to update configuration dynamically. POST to /api/config/cameras/{camera_name} with the new detect.fps value. Frigate's CameraConfigUpdateSubscriber processes this change immediately, and the watchdog adjusts its thresholds on the next evaluation cycle without requiring a full service restart.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →