| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Attendances (hr_attendance)
• Discuss (mail) • Employees (hr) |
| Community Apps Dependencies | Show |
| Lines of code | 4541 |
| Technical Name |
eh_hr_face_liveness |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Versions | 16.0 17.0 18.0 19.0 |
Attended Face Capture
An auditable blink-prompt step on the face kiosk that records what the browser reported, honestly labelled as client-asserted, not a server-verified anti-spoofing claim.
Why this module
Attended Face Capture
Labelled for what it is
Every recorded outcome carries a client-asserted flag and help text stating the server did not verify it. No record in this module can be read as proof a real person was present. The honesty is in the schema, not just the brochure.
One readonly row per attempt
Passed, failed, or aborted, with timestamp, prompt shown, duration, reported blink count, fail reason, device and site. Create and edit are off in the UI; only an admin group can delete. A matching kiosk event is logged alongside each attempt.
Per-company, throttled, swept
A global record rule scopes every check to its company. The config and log endpoints authenticate by device token and rate-limit each caller. A daily cron deletes rows past the per-company retention horizon in bounded batches.
Day in the life
Check-in at a shared kiosk, with a paper trail
An employee steps up to the face kiosk. Because attended capture is enabled for that company, the screen asks them to blink slowly twice. The browser counts the blinks with face-api.js and, after the required count or a timeout, posts the outcome. The server writes one audit row, marked client-asserted, plus a kiosk event, then the normal face-match capture proceeds. Weeks later, when an attendance entry is disputed, a manager opens Attended captures, filters to that day and site, and sees the recorded prompt, blink count, and outcome for the attempt. It does not prove identity, and the row says so, but it shows an attended-capture step happened and what the device reported.
Edge cases
The cases most modules quietly ignore.
In the shipped code today, each one a place where a cheaper module silently does the wrong thing.
If face-api.js is not loaded or getUserMedia is refused, the browser records the attempt as aborted with the underlying reason rather than silently passing or blocking check-in.
Detection runs against a deadline. Reaching the required blink count resolves as passed and stops the camera; hitting the timeout first resolves as failed with reason timeout.
The log endpoint rejects any outcome other than passed, failed, or aborted with a 400, so the audit table can never hold an out-of-enum value.
Both config and log endpoints require a valid active device token; a missing or unknown token returns 401, and no audit row is created.
Each caller, keyed by device token or client IP, is rate-limited per window on both config and log, returning 429 when over budget so a chatty or hostile client cannot flood the audit table.
A global ir.rule restricts every liveness check to the company that owns it, and each row stores its company explicitly so multi-company tenants stay separated.
The daily cron walks companies, applies each company's retention horizon (default 180 days), deletes in batches capped at 2000 rows per run, and reports progress when run under the scheduler.
Prompt and fail-reason text from the client are truncated to 255 characters on write, so a malformed or oversized payload cannot break the insert.
What is inside
Built to do the job, end to end.
- Attended capture record. eh.hr.liveness.check stores one readonly row per attempt: outcome, recorded-on timestamp, prompt shown, duration in ms, reported blink count, fail reason, device, site, optional employee, and company. A client-asserted boolean is always true by design.
- Kiosk endpoints. GET /eh_hr/kiosk/liveness/config returns the company's enabled flag, required blinks, and timeout. POST /eh_hr/kiosk/liveness/log records the reported outcome and writes a kiosk audit event. Both are device-token authed and throttled.
- In-browser blink prompt. The kiosk shell loads liveness.js, which counts blinks from the eye-aspect-ratio of face-api.js landmarks and reports passed, failed, or aborted. Detection runs in the browser only; the server records, it does not verify.
- Settings and retention. Per-company fields for enable, prompted blinks, timeout, and retention days are exposed in Settings. A daily cron sweeps rows past each company's horizon in bounded batches.
- Access and isolation. Managers and auditors get read access to the audit list; only the admin group can delete. A global record rule scopes every row to its company. The list view is create-false and edit-false.
Honest about the edges
What this does not do, so nothing surprises you.
- Not a liveness or anti-spoofing control. The outcome is computed entirely in the browser and recorded as reported; the server does no detection, no ML verification, and no spoof checks.
- A printed photo or a screen held to the camera is not detected. A recorded passed outcome must not be treated as proof a real person was present.
- Anyone who controls the kiosk device can report any outcome to the log endpoint within the rate limit. Trust is in the audit trail, not in the value itself.
- Blink detection accuracy depends on the browser, camera, and lighting, and on face-api.js being loaded by the kiosk; it is a prompt-and-count aid, not a calibrated biometric.
- Requires the ERP Heritage face kiosk modules (eh_hr_face_kiosk, eh_hr_attendance_base, eh_hr_core). It is the audit layer beneath a kiosk, not a standalone attendance system.
- For genuine anti-spoofing, integrate a separate server-side passive-liveness model; this module sits beneath such a control, it does not replace it.
Odoo 16 face attendance, face kiosk check-in, attended face capture, kiosk attendance audit, blink prompt attendance, hr_attendance face capture, kiosk liveness log, attendance dispute resolution, Odoo 16 Community HR, per-company attendance audit, face kiosk audit trail, client-asserted capture record
Please log in to comment on this module