IoT and AI

Frigate MQTT Events Explained: Topics, Payloads and Remote Alerts

Learn what Frigate NVR publishes over MQTT, how to read the frigate/events payload and how to forward only the detections that matter to a cloud broker for remote notifications.

Frigate MQTT diagram with security cameras, an NVR detecting a person and an event message travelling to a cloud MQTT broker
Run this on your own MQTT brokerGet a private, managed MQTT broker on the Free plan and start from ready-made code samples.
Try it free Code samples No card required

Frigate MQTT integration is how the Frigate NVR tells the rest of your system that it saw a person, a car or a dog, and it is the cleanest way to build alerts and automations on top of local object detection. In this guide you will learn every topic Frigate publishes, what the event payload actually contains, and how to forward only the important detections from your local network to a cloud broker so you can receive them anywhere.

How Frigate Uses MQTT

Frigate runs object detection on your camera streams locally, usually with a Coral, Hailo, OpenVINO or GPU detector. Recording and clip review happen in its web UI, but everything event-driven goes out over MQTT. Frigate is an MQTT client: it connects to a broker you specify, publishes state and events, and subscribes to a handful of command topics so you can switch detection, recording or snapshots on and off remotely.

That design means Frigate does not care who consumes the data. Home Assistant, Node-RED, a Python script or a phone MQTT app can all subscribe to the same topics at once. If you are new to the pub/sub model, it helps to understand what an MQTT broker does before wiring things together.

Configuring the MQTT Section in Frigate

The mqtt block in Frigate's config.yml points it at a broker. Most installations run a local Mosquitto container next to Frigate:

mqtt:
  enabled: true
  host: mosquitto        # container name or IP of the local broker
  port: 1883
  topic_prefix: frigate  # every topic starts with this
  client_id: frigate     # must be unique on the broker
  user: frigate
  password: "{FRIGATE_MQTT_PASSWORD}"
  stats_interval: 60     # seconds between frigate/stats messages

cameras:
  driveway:
    mqtt:
      enabled: true      # publish snapshots for this camera
      timestamp: false
      bounding_box: true
      crop: true
      height: 270
      quality: 70

Two settings cause most support threads. First, client_id must be unique: if two Frigate instances share the default frigate ID on one broker, they will kick each other off in a loop. Second, if you change topic_prefix, every automation that listens on frigate/... must change too.

Frigate MQTT Topics Reference

These are the topics you will use most often, assuming the default frigate prefix:

Topic Payload Use it for
frigate/available online / offline NVR health; Frigate sets this as its Last Will
frigate/events JSON with type, before, after Tracked object lifecycle: new, update, end
frigate/reviews JSON review item Grouped alerts and detections (newer versions)
frigate/<camera>/<object> Integer count How many of that object are in view right now
frigate/<camera>/<object>/snapshot JPEG bytes Best snapshot of the current object
frigate/<camera>/motion ON / OFF Raw motion state
frigate/<camera>/detect/set ON / OFF Command: enable or disable detection
frigate/<camera>/detect/state ON / OFF Current detection state
frigate/stats JSON Detector inference speed, CPU, camera FPS

Similar set/state pairs exist for recordings, snapshots and motion detection. Check the official Frigate MQTT documentation for your version, because newer releases add topics such as review items and tracked object updates.

Reading the frigate/events Payload

Every tracked object produces a sequence of messages on frigate/events: one new, several update messages as the object moves or the score improves, and one end when it leaves. Each message carries the full object state before and after the change. A trimmed example:

{
  "type": "new",
  "before": { "id": "1729076512.48-ab12cd", "label": "person", "top_score": 0.0 },
  "after": {
    "id": "1729076512.48-ab12cd",
    "camera": "driveway",
    "label": "person",
    "score": 0.82,
    "top_score": 0.84,
    "false_positive": false,
    "start_time": 1729076512.48,
    "end_time": null,
    "current_zones": ["front_path"],
    "entered_zones": ["front_path"],
    "has_snapshot": true,
    "has_clip": false
  }
}

The fields that matter for alerting:

  1. after.id is stable for the lifetime of the object; use it to deduplicate.
  2. after.top_score is the best confidence seen so far, which is more reliable than the instantaneous score.
  3. after.false_positive becomes false once Frigate is confident the object is real. Alerting before that point produces noise.
  4. after.entered_zones lets you alert only when someone actually walks onto the path, not when they pass on the street.
  5. type: end with end_time set closes the event and is the right moment to fetch the clip through Frigate's HTTP API.

A common mistake is triggering on every update. A person walking across a frame can generate many updates, so a naive automation sends a burst of notifications for one visit.

Why Forward Frigate Events to a Cloud Broker

The local broker is perfect inside the house or site, but it is not reachable from your phone on mobile data without opening ports, and exposing Mosquitto to the internet is a security problem. The safer pattern is outbound only: a small forwarder on the same network subscribes to the local broker, filters events and publishes compact JSON to a cloud MQTT broker. Your phone, a remote dashboard or a second site subscribes there. Nothing listens on your home router.

Forwarding also lets you strip the payload down. Snapshots can be tens of kilobytes and the public test area accepts at most 64 KB per message, so the forwarder sends metadata only and leaves images on the local Frigate server.

You could point Frigate directly at a remote broker by changing host and port and setting client_id to the client ID issued with your credentials, because ConnectMQ binds client IDs to credentials. In practice a filter in between is better: Home Assistant keeps working locally if the internet drops, and only meaningful events leave the network.

Python Forwarder: Local Frigate to ConnectMQ

The script below uses paho-mqtt 2.x. It subscribes to the local broker, forwards one message when a person or car becomes a confident detection and one when it ends, mirrors Frigate's availability, and relays a remote detect on/off command back to Frigate.

pip install "paho-mqtt>=2.0"
import json
import os
import uuid

import paho.mqtt.client as mqtt

LOCAL_HOST = os.getenv("LOCAL_HOST", "localhost")
LOCAL_USER = os.getenv("LOCAL_USER")
LOCAL_PASS = os.getenv("LOCAL_PASS")

REMOTE_HOST = os.getenv("REMOTE_HOST", "broker.connectmq.com")
REMOTE_PORT = int(os.getenv("REMOTE_PORT", "1883"))
REMOTE_USER = os.getenv("REMOTE_USER")          # unset for the public test area
REMOTE_PASS = os.getenv("REMOTE_PASS")
REMOTE_CLIENT_ID = os.getenv("REMOTE_CLIENT_ID", f"frigate-fwd-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("REMOTE_PREFIX", f"connectmq/demo/{uuid.uuid4().hex[:8]}/frigate")

LABELS = {"person", "car"}
MIN_SCORE = float(os.getenv("MIN_SCORE", "0.75"))
forwarded = set()   # event ids already announced

# ---------- remote (cloud) client ----------
remote = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=REMOTE_CLIENT_ID)
if REMOTE_USER:
    remote.username_pw_set(REMOTE_USER, REMOTE_PASS)
if REMOTE_PORT == 8883:
    remote.tls_set()
remote.will_set(f"{PREFIX}/forwarder/status", "offline", qos=1, retain=True)


def on_remote_connect(client, userdata, flags, reason_code, properties):
    print("remote connected:", reason_code)
    client.publish(f"{PREFIX}/forwarder/status", "online", qos=1, retain=True)
    client.subscribe(f"{PREFIX}/cmd/+/detect", qos=1)


def on_remote_message(client, userdata, msg):
    camera = msg.topic.split("/")[-2]
    value = msg.payload.decode().upper()
    if value in ("ON", "OFF"):
        local.publish(f"frigate/{camera}/detect/set", value)
        print(f"relayed detect {value} to {camera}")


remote.on_connect = on_remote_connect
remote.on_message = on_remote_message

# ---------- local (Frigate) client ----------
local = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"frigate-fwd-local-{uuid.uuid4().hex[:6]}")
if LOCAL_USER:
    local.username_pw_set(LOCAL_USER, LOCAL_PASS)


def on_local_connect(client, userdata, flags, reason_code, properties):
    print("local connected:", reason_code)
    client.subscribe([("frigate/events", 0), ("frigate/available", 0)])


def on_local_message(client, userdata, msg):
    if msg.topic == "frigate/available":
        remote.publish(f"{PREFIX}/nvr/status", msg.payload, qos=1, retain=True)
        return

    event = json.loads(msg.payload)
    after = event["after"]
    if after["label"] not in LABELS or after.get("false_positive", True):
        return

    event_id = after["id"]
    if event["type"] in ("new", "update"):
        if event_id in forwarded or after["top_score"] < MIN_SCORE:
            return
        forwarded.add(event_id)
        state = "started"
    elif event["type"] == "end":
        if event_id not in forwarded:
            return
        forwarded.discard(event_id)
        state = "ended"
    else:
        return

    summary = {
        "id": event_id,
        "camera": after["camera"],
        "label": after["label"],
        "score": round(after["top_score"], 2),
        "zones": after.get("entered_zones", []),
        "state": state,
        "start": after["start_time"],
        "end": after.get("end_time"),
    }
    topic = f"{PREFIX}/{after['camera']}/{after['label']}/event"
    remote.publish(topic, json.dumps(summary), qos=1)
    print("forwarded", topic, summary["state"], summary["score"])


local.on_connect = on_local_connect
local.on_message = on_local_message

remote.connect(REMOTE_HOST, REMOTE_PORT, keepalive=60)
remote.loop_start()
local.connect(LOCAL_HOST, 1883, keepalive=60)
print("forwarding to", PREFIX)
local.loop_forever()

Run it on the Frigate host, then watch the remote side from any machine. Use the prefix the script printed:

mosquitto_sub -h broker.connectmq.com -p 1883 -i watcher-7f3a2c \
  -t 'connectmq/demo/<your-id>/frigate/#' -v

Walk in front of a camera and you should see exactly two messages per visit: started and ended. To test the command path, publish OFF to connectmq/demo/<your-id>/frigate/cmd/driveway/detect.

The public test area is readable by anyone who guesses the topic, so treat it as a sandbox only. For a real home or site, create a private broker, set REMOTE_PORT=8883 and the REMOTE_USER, REMOTE_PASS and REMOTE_CLIENT_ID values from the portal. Do not run the command relay on a public topic.

Receiving Alerts on Your Phone

Because the cloud broker speaks plain MQTT, anything that can subscribe can alert you: an MQTT client app on your phone, a Node-RED flow that sends a push message through a notification service of your choice, or a remote Home Assistant instance. If you build a browser dashboard, connect over secure WebSocket on port 8084 with the /mqtt path. On the ConnectMQ portal, the live topic explorer shows the forwarded events arriving, which is handy while you tune MIN_SCORE and zones.

Troubleshooting Frigate MQTT

  1. Frigate logs "Unable to connect to MQTT server". Check that host resolves inside the Frigate container; localhost there is the container itself, not the host machine.
  2. Connection drops every few seconds. Two clients are using the same client ID. Give Frigate and every forwarder a distinct ID.
  3. No events, but the UI shows detections. The object may not be in the camera's objects.track list, or a required_zones setting is filtering it.
  4. Too many alerts. Alert on top_score and entered_zones, ignore update after the first forward, and add per-camera cooldowns if needed.
  5. Snapshots rejected on the remote broker. They exceed the message size limit; keep images local and send links or metadata.

For deeper detection pipelines, see how YOLO object detection over MQTT works or how to build person detection on an ESP32-CAM, and the AI and IoT guide for the bigger picture.

Get Remote Frigate Alerts with ConnectMQ

A private cloud broker is the missing piece between a local NVR and alerts you can trust away from home. ConnectMQ is a fully managed MQTT service with TLS on port 8883, generated credentials and a topic explorer for debugging. Start on the free Serverless plan at app.connectmq.com, no credit card required, then point the forwarder at your new broker.

Frequently Asked Questions

Does Frigate need an MQTT broker?

MQTT is optional for recording and the web UI, but the Home Assistant integration and all event-driven automations depend on it. Most users run Mosquitto on the same host.

What is the difference between frigate/events and frigate/reviews?

frigate/events describes individual tracked objects through their lifecycle. Review items group activity into alerts and detections that match what you see in the review UI, which is often better for notifications.

Can I send Frigate snapshots to a cloud broker?

Only if they fit the broker's message size limit, which is 64 KB on the public test area. Sending metadata and fetching images from Frigate's API on demand is usually cleaner and cheaper.

Is it safe to expose my local Mosquitto broker instead?

It is not recommended. An outbound forwarder to an authenticated TLS broker avoids opening ports on your router and keeps the local broker private.

Related articles

All articles →

Your private MQTT broker is a few clicks away

Create an account, get your broker credentials and connect your first device — no servers to install, patch or scale.