Configuration
Every option below is passed to FaceCaptureSession — directly in core, or through MeeeetUpCamProvider on web and useFaceCaptureSession on React Native. Each one defaults to the behaviour the SDK has always had, so an integration that sets nothing keeps working exactly as before.
Capture gates
| Option | Default | What it does |
|---|---|---|
minDetectionScore |
0.5 |
Detector confidence (0–1) a detection needs to be tracked at all. Raise it in noisy scenes where the detector boxes doorframes and posters. |
minFaceHeight |
0 (off) |
Minimum face-box height as a fraction of frame height (0–1). The cheapest way to ignore people in the background: nothing smaller is tracked, scored or cropped. |
minFrontalness |
50 |
Pose score (0–100) a frame needs to count as a usable frame of that face. Below it, the face is tracked but never captured. |
captureWindowMs |
0 (off) |
Length of the best-shot search window per face. 0 keeps the classic settle-based capture. |
cooldownMs |
10_000 |
Minimum gap between captures of the same face. With a window set, this is how long a face waits before it can be captured again. |
Two more options matter less often:
| Option | Default | What it does |
|---|---|---|
batchIntervalMs |
10_000 |
Passive only: how often buffered faces are handed to onBatchCapture. |
maxFacesPerRequest |
50 |
How many faces one batch may contain. Match it to your backend’s per-request cap. |
Detector confidence is not pose
minDetectionScore answers is there a face here. minFrontalness answers is this face looking at me. They are deliberately separate: ML Kit pins its confidence at 1.0 while MediaPipe reports 0.70–0.95, so folding one into the other would silently tighten your quality threshold on web only.
The best-shot window
Without captureWindowMs, the SDK captures a face when its pose score stops improving — it smooths the score, waits for the peak to hold for ten frames, and commits. That is right for a camera watching a corridor, where faces arrive and leave on their own schedule.
It is wrong for a kiosk. Somebody standing in front of a screen produces a stream that never settles, and the ten-frame wait plus a ten-second cooldown means the frame chosen at half a second can never be replaced by the better one at a second and a half.
Set captureWindowMs and each face gets a bounded search instead:
- The window opens on the first frame of that face worth capturing — tracked for 300 ms, three frames at or above
minFrontalness. - While it is open, every frame that beats the held one replaces it immediately and is published with
final: false. - When the window expires the held frame is published once more with
final: true, and that face is decided.
const session = new FaceCaptureSession({
sessionType: "interactive",
captureWindowMs: 2_000,
minFrontalness: 55,
onSelect: (face) => {
setPreview(face.dataUrl); // updates live as the subject improves
if (face.final) commit(face); // the photo
},
});
The window is per face, which is what lets one mechanism serve both modes: an interactive session has a single subject and therefore a single window, while a passive session runs an independent window for every face in the room.
The clock only runs while the face is there
Window time accrues on frames the face actually appears in. A subject who steps out of shot and returns does not lose their window, and a tab that gets throttled in the background does not spend it either — a single gap longer than 250 ms counts as 250 ms. “Search for two seconds” means two seconds of the subject being present.
Re-arming
A closed window stays closed, so a kiosk does not keep re-photographing the person still standing there.
- Passive: the face re-arms itself once
cooldownMshas elapsed since the window closed. - Interactive: call
session.rearm()— orcam.rearm()fromuseMeeeetUpCam()— when you want the next capture. This is the “retake” button.
A face that goes out of frame mid-window is finalised with whatever it had: leaving with the best available frame beats leaving with nothing.
Choosing thresholds
The numbers depend on lens, lighting and how far away people stand, so measure rather than guess — the live demo puts all four gates on sliders with the current readings next to them, and the frame it captures is the frame this configuration would have sent.
Sensible starting points:
| Deployment | Settings |
|---|---|
| Reception desk, one subject at a time | captureWindowMs: 2000, minFaceHeight: 0.2, minFrontalness: 55 |
| Doorway, people walking past | captureWindowMs: 0, minFaceHeight: 0.12, cooldownMs: 30_000 |
| Wide room, several faces at once | captureWindowMs: 3000, minFaceHeight: 0.08, minFrontalness: 45 |
What you receive
Every selection arrives as a SelectedFace:
| Field | Meaning |
|---|---|
trackId |
Stable for as long as that face is tracked. |
dataUrl |
256×256 JPEG data URI, ready to POST. |
frontalness |
The pose score of the frame that was chosen, 0–100. |
final |
false while a window may still replace this frame, true once it cannot. Always true without a window. |
createdAt |
When the face was first seen. |
lastSentAt |
When this selection was published. |
Identity is not the SDK’s job: two trackIds are two tracks, not necessarily two people. Deduplication and recognition belong to whatever receives the images.