Skip to main content

Liveness

A liveness check (also called a spoof check) decides whether a detected face belongs to a real, present person or to a presentation attack: a face shown on a screen, a printed photo, a 2D or 3D mask. Face Matcher provides passive liveness only: the person does not have to perform any action, which keeps the flow seamless for access control and corridor use cases. Neural networks trained on real faces and on the attack types above return a liveness score, and a threshold turns it into pass or fail.

Presentation attack with a printed face, rejected by passive liveness

Two liveness types​

TypeOptimised forTypical input
DistantFaces captured "in the wild" by surveillance-style cameras.Camera streams, corridor and gate cameras. Not recommended for selfies.
NearbyClose-up faces.Selfies, kiosk and enrollment images.

The liveness service preloads both (Warmup__LivenessAlgorithms=Distant,Nearby); the distant network variant is chosen with Liveness__DistantAlgorithm (default fast). Both types can be requested for the same face; the response then aggregates them.

Inputs and flow​

Liveness is available in three places, each with a slightly different flow:

  1. Live video processing, configured per camera or edge stream. By default only matched faces are evaluated (SpoofDetection__SkipUnidentified=true in .env); an unmatched face gets no liveness result. Set the variable to false to evaluate every face. Edge streams that compute liveness on the device follow their own liveness strategy, see Edge streams.
  2. Direct REST call POST /api/v1/Faces/SpoofCheck: no matching is performed, liveness is always evaluated.
  3. Watchlist search POST /api/v1/Watchlists/Search with liveness enabled: same rule as live video, only matched faces are evaluated.

The quality rule "better input, better result" applies to liveness even more than to matching. Minimum requirements for the input: a frontal face, enough background around the face, the face not at the edge of the image, no strong backlight or sidelight, no over- or under-exposure, and no cropping or re-compression between capture and processing.

Conditions​

Before a liveness network runs, the face must satisfy a condition string. If it does not, the check is reported as not performed with the failed condition as reason. Each liveness type has its own default set; the defaults are recommended unless the environment demands otherwise.

Distant default: FACE_CONFIDENCE: [1000; 10000]. Additional attributes you can add, with the values used in the extended example:

AttributeMinMaxMeaning
FACE_CONFIDENCE100010000Detector confidence of the face.
FACE_SIZE30infLarger of eye distance and eye-to-mouth distance, in pixels.
FACE_RELATIVE_AREA0.09infFace area relative to the image area.
FACE_RELATIVE_AREA_IN_IMAGE0.9infShare of the face that is inside the image.
YAW_ANGLE / PITCH_ANGLE-2020Head rotation around the vertical / horizontal axis (DIN 9300).
SHARPNESS_RAW500070000Sharpness before normalization.
BRIGHTNESS_RAW40000230000Raw brightness of the face area.
CONTRAST_RAW1000090000Raw contrast of the face area.
SPECULARITY_RAW500080000Raw specular reflection of the face area.

Nearby default: FACE_CONFIDENCE: [1000; 10000]. Extended example values:

AttributeMinMaxMeaning
FACE_CONFIDENCE100010000Detector confidence of the face.
FACE_SIZE60infFace size in pixels.
FACE_RELATIVE_AREA0.25infFace area relative to the image area.
YAW_ANGLE / PITCH_ANGLE-2020Head rotation (DIN 9300).
BRIGHTNESS-78005000Exposure of the face area (-10000 dark, 10000 light).
CONTRAST-50006000Contrast of the face area (-10000 low, 10000 high).
SHARPNESS_RAW4000infSharpness before normalization.
UNIQUE_INTENSITY_LEVELS50010000Number of distinct intensity levels in the face area.

Conditions are written as ATTRIBUTE: [min; max] joined with &&, for example FACE_CONFIDENCE: [1000; 10000] && FACE_SIZE: [60; inf] && YAW_ANGLE: [-20; 20].

Thresholds​

The liveness score is compared with a threshold per type: distantLivenessScoreThreshold and nearbyLivenessScoreThreshold, default 90 each. A higher threshold resists spoofing better but rejects more genuine users under difficult light; a lower one is more tolerant. How the threshold shapes false-accept and false-reject rates is discussed in Accuracy and thresholds.

The SpoofCheck call​

POST /api/v1/Faces/SpoofCheck takes an image, the detectors to run and the configuration:

"spoofDetectorResourceIds": ["liveness_distant_any_remote"],
"spoofCheckConfig": {
"distantLivenessScoreThreshold": 90,
"nearbyLivenessScoreThreshold": 90,
"distantLivenessConditions": "default",
"nearbyLivenessConditions": "default",
"keepEvaluatingConditionsAfterFirstFail": false
}
ParameterValues
spoofDetectorResourceIdsliveness_distant_any_remote, liveness_distant_cpu_remote, liveness_distant_gpu_remote, liveness_nearby_any_remote, liveness_nearby_cpu_remote, liveness_nearby_gpu_remote, or none. GPU values need GPU acceleration.
distantLivenessConditions, nearbyLivenessConditionsdefault or a custom condition string.
keepEvaluatingConditionsAfterFirstFailtrue reports every failed condition instead of only the first.

The response reports the aggregate and each type separately:

{
"performed": true,
"passed": true,
"distantLivenessSpoofCheck": {
"performed": true, "passed": true, "score": 97,
"notPerformedReasons": []
},
"nearbyLivenessSpoofCheck": {
"performed": false, "passed": false, "score": 0,
"notPerformedReasons": [{ "reasonMessage": "FACE_SIZE" }]
}
}

performed is true when the conditions were met and the network ran; passed is true when the score reached the threshold. When a check was not performed, notPerformedReasons names the conditions that failed.

SpoofCheck response flow: conditions, performed, passed

The same fields appear on match events and in Station as Distant check / score and Nearby check / score, see Events and face metadata.