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.

  1. 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, and frigate_detection_fps.

  2. 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 of ffmpeg.py) indicate configuration mismatches.

  3. Validate Queue Health

    Compare camera_fps against process_fps. A significant gap indicates frame drops. Check frigate_skipped_fps metrics (line 90 in ffmpeg.py) to confirm queue saturation.

  4. Measure Hardware Utilization

    Run nvidia-smi for GPU inference or top for CPU detection. If utilization hovers near 100% while detection_fps lags behind process_fps, your model requires more resources than available.

  5. Verify Stall Counts

    Ensure frigate_stalls_last_hour remains 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), and detection_fps (inference output rate) tracked in CameraMetrics.
  • Watchdog protection: The system restarts FFmpeg if camera_fps exceeds detect.fps + 10 to prevent resource exhaustion.
  • Queue drops: When overwhelmed, Frigate skips frames (tracked in skipped_fps) rather than falling infinite behind.
  • Tuning approach: Adjust detect.fps in config.yml or via REST API, then validate through the /metrics endpoint and watchdog logs.
  • Key files: Monitor frigate/video/ffmpeg.py for capture logic and frigate/video/detect.py for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →