# How to Debug Frigate Detection Performance and Tune FPS: A Complete Guide

> Debug Frigate detection performance by monitoring camera, process, and detection FPS. Tune detect FPS for optimal hardware performance and prevent watchdog restarts easily.

- Repository: [Blake Blackshear/frigate](https://github.com/blakeblackshear/frigate)
- Tags: how-to-guide
- Published: 2026-05-25

---

**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`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/ffmpeg.py), the `capture_frames()` function continuously updates this value using an `EventsPerSecond` tracker:

```python
fps.value = frame_rate.eps()

```

You can find this logic at lines 89‑90 of [`frigate/video/ffmpeg.py`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/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:

```python
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`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/detect.py) at lines 555‑556:

```python
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`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/ffmpeg.py):

```python

# 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`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/ffmpeg.py) at lines 21‑23, queue-full conditions increment a skip counter:

```python
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:

   ```bash
   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:

   ```bash
   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`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/config.yml) to set realistic targets based on your hardware capabilities:

```yaml
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`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/detect.py).

### Runtime Adjustment via REST API

Modify FPS without service interruption using the configuration endpoint:

```bash
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:

```python
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`](https://github.com/blakeblackshear/frigate/blob/main/ffmpeg.py) and `process_frames()` in [`detect.py`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/config.yml) or via REST API, then validate through the `/metrics` endpoint and watchdog logs.
- **Key files**: Monitor [`frigate/video/ffmpeg.py`](https://github.com/blakeblackshear/frigate/blob/main/frigate/video/ffmpeg.py) for capture logic and [`frigate/video/detect.py`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/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`](https://github.com/blakeblackshear/frigate/blob/main/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.