FaceID — trainable face recognition for Frigate with a proper review UI (Home Assistant app + standalone)

Like many here, I run Frigate and wanted reliable person recognition to drive automations (“notify me when the kids come home”, “stranger at the door at night”).

Why I built yet another tool

I looked hard at what exists before writing my own — and none of it fit:

  • Frigate’s built-in face recognition: the recognition itself is decent, but the workflow didn’t work for me. The train tab keeps refilling with already-known faces, there’s no grouping of unknowns, and strangers (hello, mailman) kept getting matched to family members because there’s no clean “unknown person” concept.

  • Double Take, the classic answer, is unmaintained (forks exist, but the ecosystem is fragmenting) — and it still needs a separate detector service behind it.

  • CompreFace is solid but heavyweight (a multi-container stack with its own DB), and it knows nothing about Frigate — you still need glue for sub_labels, sensors and review workflows.

So I built the missing piece as one small service, and I’m sharing it — open source (MIT), fully local, no cloud: GitHub - SkyTechNerds/faceid

What it does

  • Listens to Frigate person events via MQTT, grabs the snapshot crop and runs InsightFace/ArcFace on it — the same open model family Immich and CompreFace use (the ~300 MB model pack is downloaded once from the official InsightFace GitHub release; after that, everything is 100% offline).

  • Matching is nearest-neighbor over embeddings: every face you assign is a visible reference point, with no training cycles. Not immune to bad data — an imbalanced gallery biases borderline matches — but the failure mode is an image you can see and delete. There are knobs for this (a per-person photo cap, and how many reference photos a score averages over); see the measurement note below before touching them.

  • Unknown faces are auto-clustered (like your photo app does) and land in a review UI: one click assigns a whole cluster to a person. Regular strangers become their own “person” — and you can even automate on them.

  • One-click history scan: pull faces from your past Frigate events into the review queue, pre-clustered — you get a trained gallery on day one, no CLI needed.

  • Sharper reference photos: Frigate detects on a downscaled stream but records in full resolution. Faces heading for the review queue are re-fetched from the event clip — typically twice the pixel size. Live recognition keeps using the fast snapshot path.

  • Recognized names go back to Frigate as sub_label — filter clips by person in Explore, including retroactively.

  • Home Assistant sensors via MQTT discovery: one per camera with a presence window (“Alice, Bob” → “nobody”), plus an event topic for automations (example automation with snapshot notification ships in the repo).

  • Ignore list: people you simply don’t care about become negative anchors — never notified, never matched to your family, never resurfacing in review. New looks are auto-learned only on unambiguous matches (guarded, visible, reversible), and anchor groups can be merged, curated or released into a real person.

  • Measure instead of guess: two scripts report what each person is actually missing (viewing angles, cameras, day vs IR shots) and whether your last enrolling session helped — leave-one-out against your own gallery plus a probe on recent events.

Install

As a Home Assistant app (HAOS/Supervised — apps were formerly known as add-ons):

Add the repository to your Home Assistant with one click

— or manually: Settings → Apps → App Store → ⋮ → Repositories → add

https://github.com/SkyTechNerds/faceid. Then install the FaceID app, set your Frigate URL and MQTT broker in the options. The review UI shows up in the sidebar (ingress, behind your HA login).

Docker (for HA Container/Core, where apps aren’t available): docker compose up -dcompose file in the repo. Built locally; no prebuilt image on a registry yet.

Standalone (LXC/VM/bare metal): venv + systemd, ~5 minutes — step-by-step in the README.

Runs CPU-only (any AVX-capable x86, ~1.5 GB RAM; aarch64 builds too — no GPU, no Coral needed). :warning: One gotcha I hit myself: if HAOS runs in a VM, set the CPU type to host (the default kvm64 hides AVX).

On the defaults — measure yours

I shipped cautious defaults and later measured them against my own 128-photo gallery, with ground truth. Two of them were costing me half my recognitions: the score averaged the 3 best-matching photos (which penalises exactly the people with many reference angles), and the 0.50 threshold sat precisely on the median of correct matches — while a different person never scored above 0.31 on my cameras.

Adjusting both took a held-out test set from 90% to 100% recognised, without a single misassignment. Your cameras are not mine, so please don’t copy my numbers — the scripts above exist so you can find yours. Details in the README.

Honest notes

  • Recognition quality stands and falls with your camera: faces need to be reasonably large and lit. Doorbell-height cameras work great; a wide parking-lot cam won’t identify anyone. Distance/DORI matters more than the model.

  • Biometric data stays 100% on your box. The standalone UI has optional Basic Auth — still, keep it LAN/ingress only.

  • Young project — I run it in production at home, but expect rough edges. Feedback, issues and PRs are very welcome!


Update (July 26): v0.6.8 — Docker image, sharper reference photos pulled from event clips, coverage/measurement scripts, and recovery of events MQTT never announces. See the changelog.

Looks really cool. Did you try speaking with the Frigate folks to see if they’d be up to implement some of these ideas in Frigate itself?

Thanks! And fair question.

I didn’t pitch it upstream as a feature request, mainly because from following the
Frigate discussions I think the current behavior is a deliberate design choice rather
than a gap: the maintainers have been explicit that they intentionally avoid
auto-learning and bulk training because careless additions degrade the model
(see their training best-practices discussion).
Frigate optimizes for “curate a small, high-quality face library by hand” — which is
a valid philosophy, it just didn’t work for me in daily use.

Some of what FaceID does also sits outside what an NVR probably should do:
embedding-gallery matching instead of trained models, clustering unknowns for review,
enrolling from your photo library, treating the mailman as a first-class “person”,
presence-window sensors in HA. That’s identity management more than video recording.

That said, everything here is MIT — if any of these ideas end up in Frigate itself,
that’s a win for everyone and I’d happily help. Until then the two compose nicely:
Frigate stays the NVR and does detection, FaceID handles the “who is it” layer on top.

All of these approaches were considered during the 6 months that I spent building the face recognition feature in Frigate. I want to be clear that creating and sharing open source projects is always a great thing, and if something solves a problem for someone it is great to see.

With that said, this post either dishonestly or perhaps unknowingly (as it appears largely AI generated) misrepresents some concepts. For example, the post says

Overfitting as a concept is inherently a problem in machine learning. All face recognition implementations I am aware of use embeddings models, and imbalanced data is entirely possible as that leads to bias towards that group. For example, if you include a large number of one persons images in a cluster then another person who has very few images is much more likely to be recognized as that person from certain angles due to this overfitting.

The clustering approach works, like how Immich does it using dbscan, but it has its own downsides that make it unsustainable for individual face recognition analysis when unknown people appear on the camera for a short time.

Typically, there is a finite group of known people that will be around the property frequently enough for it to make sense to add them to the face recognition. After that point, they are all unknown. Frigate groups the faces by the person that was detected during that time, and shows overall what it was recognized based on all of the faces.

As Frigate is open and easily extensible, projects like this make it so users always have plenty of options depending on their needs.

Thanks for taking the time — given the six months you put into Frigate’s face
recognition, this is exactly the feedback I hoped for.

You’re right on the imbalance point, and “no overfitting” was sloppy wording on my
side: nearest-neighbor over embeddings has no training cycles, but an imbalanced
gallery absolutely biases borderline matches toward the person with the most
reference images. I’ve reworded the README to say exactly that
(commit), and mitigating it
(top-k mean per person instead of raw max, plus a per-person cap) is on my list.

That said, gallery imbalance between known people wasn’t what made me build this.
My daily problem with the built-in flow was a different one: unknown people kept
being recognized as household members, and there was no workflow to make that stop
permanently — I was correcting the same mailman over and over. FaceID’s answer to
that isn’t a better model (it’s the same ArcFace family): it’s an explicit
uncertainty band that routes to a review queue instead of auto-labeling, recurring
strangers as first-class persons (so the courier matches himself instead of my
kids) — and, importantly, nothing ever enters the gallery automatically. Enrollment
is always an explicit human action, so a recognition mistake never compounds into
future ones.

Agreed on clustering’s limits — a stranger who shows up for two seconds stays a
single-image entry, no magic there. It earns its keep for the recurring
non-household people.

On the AI remark: sure, I use AI heavily — for building and for writing. After 20
years in IT I treat it like any other tool that makes me faster; not using it in
2026 would be the actual mistake. The imprecise claim above is mine to own either
way — which is why it’s already fixed.

Frigate being open and extensible is what made this possible in the first place —
genuinely appreciated.

Quick follow-up on the above: shipped.

v0.2.0 implements the imbalance mitigation discussed here — a person’s score is
now the mean of their top-k reference similarities instead of a raw max, plus a soft
per-person photo cap (most redundant reference is dropped).

v0.2.1–0.2.7 added a full ignore workflow on top: ignored people become negative
anchors (never notified, never matched to enrolled people, never resurfacing in
review), new looks are auto-learned only on unambiguous matches with a clear margin
over every enrolled person (visibly marked, deletable), anchors are grouped per
person and can be merged, curated, or released into a real person if you change
your mind.

Changelog: faceid/CHANGELOG.md at 8fce0318ef0c760de98a10a5355af97e4a7e6acf · SkyTechNerds/faceid · GitHub

Suggestion:
Add-ons have been renamed to Apps about a year ago now.

Add-ons no longer exist and building new Apps and using the words and links to the old way in the readme is very confusing for users wanting to try your stuff…

Please consider a wording revision.
A simpler approach may be to use the Create a link – My Home Assistant facility…

For instance, this install sequence doesn’t work:

Proofreading and testing the actual instructions that you copied from other sources to make sure things are right is a good best practice to follow. So is this: AI Policy | Home Assistant Developer Docs

Good catch, thank you — fixed. The README and this post now use the current Apps
naming (Settings → Apps → App Store), and the README has a My Home Assistant
one-click link for adding the repository, as you suggested. The rename slipped
past me because I’d verified the install through the Supervisor API rather than
clicking through the Settings UI — lesson taken.

The things you’ve highlighted are the biggest issues I’ve faced trying to get Frigate’s facial detection system to work. For the most part it actually does work well, but I found I needed to stay on top of it constantly to add faces and get them working well.

That in mind… unfortunately I can’t use your system as I run HA in a container and can’t use add-ons, but also don’t run Proxmox so can’t use LXC or VMs.
Do you have any plans to make this available as a Docker container?

As I also reported on GitHub, there appears to be an issue with the latest version, v0.2.7. Since updating, the app (add-on) no longer starts. I also noticed on GitHub that several other users are experiencing the same problem.

sorry about that did not check GitHub for any issues, update released bug solved FaceID add-on fails to start after updating to v0.2.7 · Issue #1 · SkyTechNerds/faceid · GitHub

Update: v0.6.8 — Docker, sharper references, and what measuring the defaults revealed

@DeLorean — sorry for the wait, and thanks for asking: FaceID now ships a plain
container
, so you no longer need the supervisor.

services:
  faceid:
    build: .
    ports: ["8600:8600"]
    volumes:
      - ./config.yaml:/opt/faceid/config.yaml:ro
      - faceid-data:/opt/faceid/data
volumes:
  faceid-data:

git clone, copy docs/example-config.yaml to config.yaml, docker compose up -d.
The model pack lands in the data volume, so an image update doesn’t re-download 300 MB.
Honest limitation: there is no prebuilt image on a registry yet — you build it locally
(~2 GB, a few minutes). If a published image would help, say so and I’ll set up the
workflow.


The part I did not expect: the defaults were leaving half the recognitions on the table.

I finally built proper measurement (scripts/measure-recognition.py, leave-one-out with
real ground truth) instead of trusting my instincts, and pointed it at my own 128-photo
gallery. Two findings, both counter to what I had assumed:

match_top_k punishes your best-covered people. A score is the mean of the k
best-matching reference photos — the very thing I added in 0.2.0 to dampen photo-count
bias, after the feedback in this thread. But for someone with 40 references spanning many
angles, one photo matches well and the next two drag the mean down. Lowering k from 3 to 1
nearly doubled correct recognitions (36 → 65) with zero misassignments, and widened
the margin to the runner-up. It’s now adjustable in Settings rather than buried in the
config file.

The threshold sat exactly on the median of correct matches. Measured on that gallery,
the right person scores a median of 0.50 — and a different person never got above
0.31. The default of 0.50 was therefore discarding half of all genuine recognitions to
keep a distance nothing ever came close to.

Together, on a held-out set of real events: 90% → 100% recognised, and my weakest
favourite went from 0.01 above the cut-off to 0.09 above it.

Please don’t copy my numbers — measure your own gallery. That’s exactly what the scripts
are for, and how far strangers get on your cameras is the number that decides how low
you can safely go.


Also since 0.2.7:

  • Sharper reference photos. Frigate detects on a downscaled stream but records in full
    resolution. Faces entering the review queue are now re-fetched from the event clip —
    typically twice the pixel size (74→144 px, 84→163 px on real events). Live recognition
    still uses the fast snapshot path.
  • scripts/coverage.py tells you what each person is actually missing: viewing angles
    estimated from the landmarks, which cameras they were enrolled from, greyscale/IR shots,
    and photo diversity. Turns “add more photos” into something specific.
  • Recovering missed events. --rescue re-checks events whose snapshot held no face by
    scanning the clip. About one in five yields a face the normal scan misses entirely.
  • Events MQTT never announces. If you bridge your camera’s own person detection into
    Frigate via its API, those events are not tracked objects and never appear on
    frigate/events — FaceID never saw them. poll_interval closes that gap; on my front
    door that was ~22 events a day, of which 12 in 20 held a usable face.
    (docs/camera-bridge.md)
  • Duplicate detection, transparent photo trimming with restore, per-photo provenance,
    and a pile of fixes — full list in the
    changelog.

Rough edges, honestly: the rescue scan is slow and downloads a clip per event, so it
is a manual run rather than something automatic. Camera quality still dominates
everything — no amount of tuning fixes a face that is 40 px and looking away. And I
shipped a broken UI for about forty minutes yesterday (a duplicate const took the whole
page down); CI now parses the frontend script on every push, which would have caught it.

Repo: GitHub - SkyTechNerds/faceid: Self-hosted face recognition for Frigate + Home Assistant — InsightFace/ArcFace matching, clustered unknown review UI, photo-library enrollment, Frigate sub_label write-back, HA MQTT sensors · GitHub

I’ve been trying to get FaceID working, but so far without success.

My setup is Home Assistant running bare metal on an x86 mini PC. Frigate is installed with two cameras and successfully recognizes both existing and newly added faces. However, FaceID does not seem to detect or recognize any faces.

I also have two additional questions:

  • Where is the FaceID backup/data folder located within the Home Assistant file system?
  • How exactly can I receive the FaceID sensors and MQTT topics in Home Assistant? MQTT itself is working correctly as an integration, but I do not yet understand how the FaceID entities and events are supposed to appear.

Any guidance on what I may be missing would be greatly appreciated.


Boot Log:


08:25:17] INFO: Starting FaceID...
2026-07-26 08:25:18,281 faceid INFO Lade InsightFace (buffalo_l) …
2026-07-26 08:25:20,010 faceid.mqtt INFO MQTT verbunden (Success)
2026-07-26 08:25:20,073 faceid.backup INFO Auto-Backup geschrieben: /opt/faceid/data/backups/faceid-backup-20260726-082520.tar.gz


@lemuba Thanks for the detailed report — you found a real bug, and question 2 is the
answer to it.

No entities appear unless you list your cameras. An empty cameras option means
“process every camera”, which is correct for recognition — but MQTT discovery iterated
over exactly that empty list and therefore announced nothing. So with a default
configuration you get no sensors at all. It never surfaced here because my own config
lists cameras explicitly. Fixed in v0.6.9: FaceID now asks Frigate for the camera
list when none is configured, and announces a camera the first time an event from it
arrives.

If you want the sensors right now without updating, filling in the cameras option with
your two camera names (exactly as they are named in Frigate) has the same effect.

Once they appear, you get one sensor per camera — sensor.faceid_<camera> — holding the
people currently seen (“Alice, Bob” → “nobody” after the presence window), plus a JSON
event on faceid/event for automations. A ready-made example automation is in the repo.

Where the data lives: inside the app container at /data/faceid (gallery, review
queue, settings, backups). It is not visible from the HA file system — apps have their
own volume. The practical way to get at it is the Settings tab → Backup, which hands
you a .tar.gz, and Restore takes it back. There is also an optional daily auto-backup;
that is what wrote the line you saw in your log.

Now to “it doesn’t recognise anything”. Your log shows the service is healthy — model
loaded, MQTT connected — but nothing after that, which means no person events are
reaching it. v0.6.9 also makes that diagnosable: on startup it now logs whether Frigate
answers and which cameras it has, e.g.

faceid.mqtt INFO Frigate erreichbar (http://192.168.x.x:5000), Kameras: front, garden
faceid.mqtt INFO MQTT verbunden (Success), abonniere frigate/events
faceid.mqtt INFO MQTT-Discovery: 2 Sensor(en) angemeldet

If instead you see “Frigate nicht erreichbar”, the Frigate URL in the app options is the
problem — from inside the app, localhost is the app itself, so it needs your host’s
LAN address.

Two more things worth checking, both of which would produce exactly your symptom:

  1. Frigate’s MQTT topic prefix. FaceID subscribes to frigate/events. If your
    Frigate config sets mqtt.topic_prefix to something else, nothing ever arrives —
    this was hard-coded until v0.6.9 and is now the frigate_topic_prefix option.
  2. Whether person events actually flow. You mention Frigate recognises faces — that
    is Frigate’s own face recognition, which is separate. FaceID needs Frigate to track
    people
    . Quick check from any machine with mosquitto-clients:
    mosquitto_sub -h <broker> -u <user> -P <pass> -t 'frigate/events' -v
    
    Walk past a camera; if nothing prints, the problem is upstream of FaceID.

If none of that lands it, post the startup lines from v0.6.9 and I’ll take another look.
Sorry for the rough edge — this one was squarely mine.

First of all, thank you for your feedback!

I’ve made some progress: FaceID now connects successfully to MQTT and Frigate, and the two camera sensors have appeared in Home Assistant. However, FaceID still does not detect any faces.

At the same time, Frigate detects me with 100% confidence while I am standing directly in front of the camera.

Log:


18:02:44  faceid  Lade InsightFace (buffalo_l) …
18:02:46  mqtt  MQTT verbunden (Success), abonniere frigate/events
18:02:46  mqtt  Frigate erreichbar (http://192.168.12.170:5000), Kameras: Terrasse_CAM, Carport_CAM
18:02:46  mqtt  MQTT-Discovery: 2 Sensor(en) angemeldet
18:02:46  backup  Auto-Backup geschrieben: /opt/faceid/data/backups/faceid-backup-20260726-160246.tar.gz
18:05:00  mqtt  Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 1, kein Gesicht >= 48px im Snapshot
18:05:04  mqtt  Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 2, kein Gesicht >= 48px im Snapshot
18:05:07  mqtt  Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 3, kein Gesicht >= 48px im Snapshot
18:05:10  mqtt  Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 4, kein Gesicht >= 48px im Snapshot
18:05:15  mqtt  Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 5, kein Gesicht >= 48px im Snapshot

The log suggests that FaceID cannot find a face at least 48 pixels in size in the Frigate snapshot, even though I am standing directly in front of the camera.

I have also attached two screenshots showing the current settings and the newly created sensors.

Is there anything else I can check or change to help FaceID detect the face correctly?

Best regards


Pls. see also the Python related error message:


[16:02:44] INFO: Starting FaceID...
2026-07-26 16:02:44,895 faceid INFO Lade InsightFace (buffalo_l) …
2026-07-26 16:02:46,431 faceid.mqtt INFO MQTT verbunden (Success), abonniere frigate/events
2026-07-26 16:02:46,437 faceid.mqtt INFO Frigate erreichbar (http://192.168.12.170:5000), Kameras: Terrasse_CAM, Carport_CAM
2026-07-26 16:02:46,438 faceid.mqtt INFO MQTT-Discovery: 2 Sensor(en) angemeldet
2026-07-26 16:02:46,493 faceid.backup INFO Auto-Backup geschrieben: /opt/faceid/data/backups/faceid-backup-20260726-160246.tar.gz
2026-07-26 16:05:00,670 faceid.mqtt INFO Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 1, kein Gesicht >= 48px im Snapshot
/opt/faceid/venv/lib/python3.11/site-packages/insightface/utils/face_align.py:23: FutureWarning: `estimate` is deprecated since version 0.26 and will be removed in version 2.2. Please use `SimilarityTransform.from_estimate` class constructor instead.
  tform.estimate(lmk, dst)
2026-07-26 16:05:04,264 faceid.mqtt INFO Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 2, kein Gesicht >= 48px im Snapshot
2026-07-26 16:05:07,373 faceid.mqtt INFO Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 3, kein Gesicht >= 48px im Snapshot
2026-07-26 16:05:10,704 faceid.mqtt INFO Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 4, kein Gesicht >= 48px im Snapshot
2026-07-26 16:05:15,643 faceid.mqtt INFO Event 1785081899.546878-evdatz (Terrasse_CAM): Versuch 5, kein Gesicht >= 48px im Snapshot

P.S.

I downloaded the Frigate event snapshot via the API and reviewed the image.

The person is detected correctly by Frigate, but the face itself appears quite small in the 640 × 480 snapshot. I estimate the face width to be only around 35–45 pixels, so it may be just below FaceID’s current minimum requirement of 48 pixels…???

The camera is also mounted high and uses a wide-angle view, so the face is seen from above and is not fully frontal. This probably makes detection more difficult, even though Frigate recognizes the person with high confidence.

Would it be possible to make the 48-pixel minimum face size configurable, for example allowing a value around 32 pixels for wide-angle cameras?

I also checked the downloaded snapshot itself, so the issue seems less likely to be MQTT or Frigate connectivity and more likely related to the face size and camera angle.

P.S. Another update: After zooming in, FaceID is now able to recognize me. However, I would still like to ask whether the 48-pixel minimum face size could be made configurable, especially for wide-angle cameras where faces may appear smaller.

Good — sensors are there, so that part is sorted. And your log now points straight at the
remaining problem:

attempt 1, no face >= 48px in the snapshot

FaceID does not work on the camera stream. It works on the snapshot Frigate stores per
event
, and that snapshot is often much smaller than what you see in the live view. So
“I’m standing right in front of the camera” and “the face in the snapshot is 30 px” are
perfectly compatible. Frigate detecting you with 100% confidence doesn’t help either —
that is person detection, which works on a body, not a face.

Please update to v0.6.13 and post that line again — it now distinguishes the two cases
that need completely different fixes, and it is finally in English (the log used to be
German, which was an oversight on my part — sorry, that can’t have helped):

attempt 1, largest face 31px < min_face_px 48 (snapshot 180x240)   → a face, but too small
attempt 1, no face detected in snapshot 180x240                    → none detected at all

If it says “too small”, check these three, in this order:

  1. snapshots.height in your Frigate config. If it is set (many configs carry
    height: 270 from an example), Frigate scales every snapshot down to that height
    before storing it, and the face shrinks with it. Remove it, or set it generously
    (1080). This costs nothing but disk and is by far the most common cause.
  2. snapshots.crop. With crop: true you get the person cut-out — usually better for
    face detection. Worth trying both.
  3. min_face_px in FaceID (default 48). Lowering it to 32 makes it try harder, but
    below roughly 40 px ArcFace embeddings get noticeably unreliable — that is a last
    resort, not a fix.

If it says “no face at all”, the snapshot resolution is not your problem — then it is
angle or light. A camera mounted high looking down at a walking person often never sees a
frontal face; Frigate happily reports “person” for a head of hair. Doorbell height works
much better than roof height.

Either way, a quick sanity check: open the event in Frigate’s Explore view, download the
snapshot and look at it at 100%. If you struggle to make out the face, FaceID will too.

Two side notes: the FutureWarning about estimate is harmless noise from the
InsightFace library, unrelated to your problem — and 0.6.11 added a LOG tab in the UI,
so you no longer need the app log to see these lines.


07:17:24  mqtt  event 1785129444.137298-qhqmkr (Terrasse_CAM): attempt 1, largest face 33px < min_face_px 48 (Snapshot 300x300)
07:17:27  mqtt  event 1785129444.137298-qhqmkr (Terrasse_CAM): attempt 2, largest face 37px < min_face_px 48 (Snapshot 316x316)
07:17:33  mqtt  event 1785129444.137298-qhqmkr (Terrasse_CAM): attempt 3, match ME (0.527)

Thanks again for your feedback and the detailed explanations!

As you can see from the log above, FaceID seems to be working as expected. In most cases, the detected faces are simply too small, which appears to be related to the camera resolution and/or the snapshots generated by Frigate.

One thing I’m still wondering about: when FaceID successfully recognizes me (as in the third attempt above), it doesn’t add a new thumbnail to the FaceID gallery. Is that the expected behavior, or should a successful recognition also create/update the gallery thumbnail?

That log is exactly what it should look like — and it answers your question in passing:

attempt 1, largest face 33px < min_face_px 48
attempt 2, largest face 37px
attempt 3, match ME (0.527)

FaceID retries while an event is running, and by the third snapshot you had come close
enough. Nothing is broken; the face is simply near the size limit on that camera.

On the thumbnail: that is deliberate, and it is the single most important design
decision in the project.
A successful recognition tags the Frigate event and updates
the sensor, but never adds to the gallery. Reference photos come only from what you
assign in the review queue, or upload yourself.

The reason: a gallery that grows from its own matches starts believing itself. One wrong
match adds a wrong reference, which makes the next wrong match easier, and within weeks
nobody can tell why a stranger is now confidently “you” — with no obvious thing to
delete. Every reference in FaceID is there because a human put it there. That is also
why bad data stays fixable: it is a picture you can look at and remove.

If you want more references for yourself, the Persons tab takes uploads (5–10 clear
photos work well), and anything landing in the review queue can be assigned with one
click. Both are visible, both are reversible.

Two things worth doing on your setup, given those numbers:

Your snapshot is 300×300, so snapshots.height is not clipping you — the face is small
because of distance and mounting height. Raising max_attempts (default 6) gives FaceID
more shots at catching the moment you are closest, which is precisely what rescued
attempt 3 above. That is cheap and safe.

Second: your match came in at 0.527 against a default threshold of 0.50 — that is a
margin of 0.03, and it will not survive worse light. Before touching min_face_px, run

python scripts/measure-recognition.py --days 3

It reports how much headroom each recognition actually has, and how high strangers
score on your cameras. On my setup strangers never passed 0.31, which meant 0.50 was far
more conservative than it needed to be. Yours will differ — but that number tells you
whether you can safely lower the threshold, which helps far more than shaving pixels off
the minimum face size.

Sorry, I meant the review queue, not the gallery.

The thumbnails are now appearing in the review queue, and I can assign them to persons as expected. I’ll play around with it a bit more and report back if I run into any issues or have further feedback.

One more question: would license plate recognition also be something you would consider implementing in the future?

Ah, the review queue — that makes much more sense, and good to hear it works. Thanks for
sticking with it through those first days; between the two of us we shook out a bug that
left everyone on a default config without any entities, so this thread was well worth it.

On licence plates: Frigate already does that, and better than I could. Since 0.16
there is a built-in lpr block:

lpr:
  enabled: true
  detection_threshold: 0.7
  recognition_threshold: 0.9
  min_plate_length: 4

Recognised plates appear as sub_label on car events, exactly like FaceID does for
people — so your automations look the same either way. Worth simply switching on and
trying.

I am not planning to build it into FaceID. It looks adjacent, but underneath it is a
different problem: faces are matched by comparing embeddings against reference images
you assign, whereas a plate is read as text by an OCR model. There is no gallery to
curate, no clustering of unknowns, no review queue — which is precisely the part FaceID
exists for. I would end up shipping a worse copy of something Frigate already has.

That said, the reason FaceID exists at all is that Frigate’s face recognition worked
fine while its workflow around it didn’t. If you try the built-in LPR and hit the same
kind of wall — no sensible way to review what it got wrong, no way to correct it — then
say so here. That would be a real argument, and a different conversation from “wouldn’t
it be nice to have”. I would rather be convinced by a concrete gap than build on
speculation.