| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Attendances (hr_attendance)
• Discuss (mail) • Employees (hr) |
| Community Apps Dependencies | Show |
| Lines of code | 4006 |
| Technical Name |
eh_hr_face_kiosk |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Versions | 16.0 17.0 18.0 19.0 |
Face Kiosk Attendance
Turn any browser tablet into a face-match clock that posts straight to hr.attendance, with raw images that never leave the device.
Why this module
Face Kiosk Attendance
The face never travels
face-api.js computes the 128-dim embedding on the device. Only that numeric vector reaches the server, and no raw image or frame is persisted. Every template is tied to a granted consent record, and withdrawing consent deactivates the related templates in the same transaction.
Straight into hr.attendance
A match toggles the employee's state: it opens a check-in or closes the latest open check-out, creating a genuine hr.attendance record. No middle layer, no nightly sync, no spreadsheet to reconcile times by hand.
A stolen token cannot run wild
The match route is paired by device token, scoped to the device's company so cross-company matching is impossible, and throttled by a DB-backed atomic counter that returns 429 over budget. Optional per-site geofencing rejects matches outside the configured radius.
Day in the life
A shift starts at the front-desk tablet
A worker steps in front of the paired iPad at reception. The browser detects the face, builds the embedding locally, and sends it to the server. The controller normalises the vector, cosine-matches it against active consented templates for that company, and finds the closest within threshold. An hr.attendance check-in is created and the screen says welcome. Eight hours later the same face closes the record as a check-out. Every attempt, pass, and failure is written to the kiosk audit trail. No badge, no PIN, no raw photo stored anywhere.
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.
When a face consent is withdrawn, every active template under it is deactivated in the same transaction and the cascade is logged to the audit trail with a count, so a later compliance review can prove what was deactivated and when.
The consent retention cron also deactivates templates whose face consent has expired, so a template never stays matchable past its consent horizon even if no one withdraws it manually.
The public match endpoint is rate-limited by a single atomic SQL upsert keyed on scope plus token or IP, shared across gunicorn or gevent workers and durable across restarts, so a leaked device token cannot hammer the endpoint or brute-force matches.
The device token resolves to one company, and candidate templates are filtered to that company id. A face enrolled in another company can never match at this layer.
When the closest template is past the configured match threshold, no attendance is posted; a match_fail event is logged and an identity_low_confidence attendance exception is raised against the nearest employee for a human to review.
For sites with geofencing enabled, a missing or out-of-radius client location returns no match with an explicit reason and logs a geofence_fail event, computed with a haversine distance against the site coordinates.
Templates reject non-JSON, non-list, non-numeric, or wrong-dimension embeddings at the model constraint layer, and the consent must be of type face and belong to the same employee, so a malformed or mismatched template cannot be stored.
What is inside
Built to do the job, end to end.
- eh.hr.face.template model. Stores the JSON embedding, declared dimension, recognition model identity and version, capture method, quality score, company, and the mandatory consent link. Constraints validate the embedding and enforce the face-type and employee match. Deactivate, reactivate, and a mail.thread audit on the record.
- Match controller. The /eh_hr/kiosk/face/match route authenticates by X-EH-Kiosk-Token, validates the embedding, optionally geofences, normalises and cosine-matches against active consented templates, applies the company threshold, and posts the check-in or check-out to hr.attendance.
- Public kiosk shell. The /eh_hr/kiosk/<site_code> route renders a standalone public HTML page that loads face-api.js and the kiosk scripts outside the Odoo web client, with pair, welcome, success, failure, and site-not-found screens and a request-time asset version stamp for cache busting.
- Enrolment wizard. An HR-admin wizard captures three to five samples through an OWL widget, requires a ticked consent acknowledgement, grants or reuses the face consent, stores each sample as its own template, and logs the enrolment to the audit trail.
- Employee integration. hr.employee gains a computed face-enrolled flag driven by active templates, an active template count, and actions to open enrolment or view templates. Roles for user, manager, admin, and auditor are wired through the suite security groups.
Honest about the edges
What this does not do, so nothing surprises you.
- This is an attendance-convenience face match, not an anti-spoofing or liveness control. A printed photo or a screen showing an enrolled face can match, and a modified client could submit any embedding. Use it to make clocking in convenient, not to prove who physically attended.
- Passive liveness is not included in this module. Liveness is provided as a separate companion module that the kiosk shell hooks into; without it, no spoof detection runs.
- face-api.js and its model files are not bundled. An operator runs a one-time setup to place the library and roughly six megabytes of model weights under static/lib/face-api before the kiosk works.
- Matching is a linear scan over active templates, which is fine for the typical site of dozens to low hundreds of employees per company. A vector index is the right answer once a company crosses roughly two thousand templates.
- The kiosk page needs camera access over a secure context and a Chromium, Firefox, or Safari browser on the local network. There is no native app and no offline match.
- Match accuracy depends on enrolment quality and the configured threshold. Varied lighting and three to five samples per employee materially improve reliability.
face recognition attendance odoo, biometric clock in odoo 17, kiosk attendance odoo, face-api.js odoo, contactless time clock, no badge attendance, employee clock in clock out, self hosted face attendance, geofenced attendance odoo, hr attendance kiosk, odoo 17 community attendance, buddy punch prevention
Please log in to comment on this module