Identity · Selfie liveness
Ask for a movement a photo cannot make.
The server issues a random sequence of challenges. The person performs them on camera, and every frame is analysed on KYCVerify's engine: one face, the same face throughout, the right movement in the right order, at a human pace.
- challenge types: turn left, turn right, smile, move closer
- 4
- challenges per session, 3 by default
- 1-4
- single-use challenge lifetime
- 5 min
What it checks
Liveness, check by check.
Each rule below is what the engine actually runs. The result is written as a liveness check with its score and warnings.
Order
Frames must arrive as a centre frame followed by each issued challenge in the issued order. Anything else is
out_of_order.Movement
Head pose is computed from five facial landmarks. A turn must change yaw in the requested direction, a smile must widen the mouth relative to the eyes, moving closer must grow the face.
Same person
Every frame's face is embedded and compared with the centre frame. A face that changes mid-sequence fails with
face_changed.One face
A second significant face in any frame fails the sequence with
multiple_faces. Small faces far in the background are ignored.Timing and replay
Timestamps must increase and span a plausible time (
too_fast). Differently labelled frames that are pixel-identical are a replayed still (frames_identical).Best selfie
The sharpest frontal frame is kept as the selfie used for face match and duplicate detection.
Try it
Play the rules, not a recording.
Issue a random challenge set the way the server does, set what the frames measured, and see the verdict of the same rules: order, timing, one face, the same face, enough movement, no replayed stills.
- The rules are ported line for line from the Rust engine, and the page names the file.
- Everything runs locally in this tab. No request is made while you type.
- Reset puts the example back; nothing is saved.
Liveness: the rules behind a verdict
The server shuffles the four and takes this many. A new set is issued on every attempt.
What the frames measured
Yaw change toward the subject's left; needs 15°.
Mouth width relative to eye distance; needs +12%.
Face width relative to image width; needs +25%.
Across all frames
Every frame's face must stay at or above 0.5.
At least 1.5 seconds.
Attempt passes: a liveness check is recorded as passed
Every liveness check records its method: “Active challenge-response liveness (head pose / expression / distance across frames). Not a certified presentation-attack-detection (ISO 30107-3) result.”
Logic ported from backend/crates/kyc-vision/src/liveness.rs. Nothing you type leaves this page.
How it works
What happens, in order.
- 1
Start
POST /flow/{token}/liveness/startreturns achallenge_idand a random list such as["turn_left", "smile", "move_closer"]. - 2
Perform
The hosted flow guides the person through each challenge and captures a centre frame plus frames per challenge, un-mirrored, with timestamps.
- 3
Analyse
The frames are posted once; the server runs detection, pose, embeddings and the rules above, and writes a
livenesscheck.
Configuration
The workflow keys and their defaults.
"liveness": { "enabled": true, "challenges": 3, "max_attempts": 3 }| Key | Default | Meaning |
|---|---|---|
| challenges | 3 | How many random challenges to issue (1 to 4). |
| max_attempts | 3 | Attempts before the step fails. |
Reference
Four challenges, measured against the centre frame.
Head pose comes from five facial landmarks found by YuNet. Each challenge is the best frame's change relative to the person looking straight ahead.
| Challenge | Measured as | Must reach |
|---|---|---|
| turn_left | Yaw change toward the subject's left | 15° |
| turn_right | Yaw change toward the subject's right | 15° |
| smile | Mouth width relative to eye distance | +12% |
| move_closer | Face width relative to image width | +25% |
| all frames | SFace cosine to the centre face | 0.5 |
| sequence | First to last frame timestamp | 1.5 s |
Reasons and warnings
Exact codes, as they appear in the check's data and warnings, so you can branch on them.
| Code | Outcome | When |
|---|---|---|
| out_of_order | attempt fails | Frames did not arrive as centre then each issued challenge, or timestamps did not increase. |
| too_fast | attempt fails | The whole sequence spanned less than 1.5 seconds. |
| multiple_faces | attempt fails | A second face at least half the width of the main one appeared. |
| face_changed | attempt fails | A frame's face fell below 0.5 cosine to the centre face. |
| challenge_failed | attempt fails | A movement did not reach its threshold. |
| frames_identical | attempt fails | Two differently labelled frames are near pixel-identical: a still image replayed. |
| liveness_unavailable | review | Face models are not installed; the frames are kept for a person to judge. |
API
Liveness runs in the hosted flow.
There is no standalone liveness endpoint: the challenge has to be issued to a live camera. Create a session whose workflow has the liveness step, then read the check from the decision.
Liveness runs in the hosted flow.
# 1. Create a session on a workflow that has the liveness step
curl -X POST https://kycverify.me/api/v1/sessions \
-H "x-api-key: $KYC_API_KEY" \
-H "content-type: application/json" \
-d '{ "workflow_id": "wf_…", "vendor_data": "user-42" }'
# 2. After the session.status_updated webhook, read the decision
curl https://kycverify.me/api/v1/sessions/ses_…/decision \
-H "x-api-key: $KYC_API_KEY"decision.checks[] · liveness
{
"kind": "liveness",
"status": "passed",
"score": 0.86,
"data": {
"attempt": 1,
"challenges": ["turn_left", "smile", "move_closer"],
"frames": 9,
"method": "Active challenge-response liveness (head pose / expression / distance across frames). Not a certified presentation-attack-detection (ISO 30107-3) result.",
"result": {
"passed": true,
"identity_consistency": 0.81,
"issues": [],
"challenges": [
{ "challenge": "turn_left", "passed": true, "measured": 21.4, "threshold": 15 }
]
}
},
"warnings": []
}Limits
What it does not do.
Stated up front, so you can decide what to pair it with.
- This is active liveness, not a certified presentation-attack-detection (PAD) model, and the check data says so. It has not been tested by a PAD lab.
- No passive liveness, no injection or virtual-camera detection, and no 3D depth sensing. A determined attacker with a real-time face-swap may defeat challenge-response.
- For high-risk flows, combine liveness with face match against the document, duplicate detection and human review.
FAQ
Liveness: questions.
Is this iBeta or ISO 30107-3 certified?
No. KYCVerify makes no PAD certification claim. Liveness is challenge-response analysed by open models on KYCVerify's engine, and it is labelled as such in every check.
Does the person need an app?
No. The hosted flow uses the browser camera on any modern phone or laptop.
Which models run?
YuNet for face detection and SFace for embeddings, both from the OpenCV model zoo, run by a pure-Rust inference runtime on your CPU.
Try it in the sandbox today.
Every check is available from the first sign-up, with test keys and a default workflow. Talk to us when you are ready to verify real people.