Skip to content

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.

kycverify · productliveness
challenge types: turn left, turn right, smile, move closer
4
challenges per session, 3 by default
1-4
single-use challenge lifetime
5 min
Active challenge-response

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

Runs in your browser
Look ahead
3

The server shuffles the four and takes this many. A new set is issued on every attempt.

Issued

What the frames measured

reached
22°

Yaw change toward the subject's left; needs 15°.

reached
+18%

Mouth width relative to eye distance; needs +12%.

reached
+31%

Face width relative to image width; needs +25%.

Across all frames

0.74

Every frame's face must stay at or above 0.5.

3.8 s

At least 1.5 seconds.

Attempt passes: a liveness check is recorded as passed

The sharpest frontal frame becomes the selfie for face match and duplicate detection.

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. 1

    Start

    POST /flow/{token}/liveness/start returns a challenge_id and a random list such as ["turn_left", "smile", "move_closer"].

  2. 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. 3

    Analyse

    The frames are posted once; the server runs detection, pose, embeddings and the rules above, and writes a liveness check.

Configuration

The workflow keys and their defaults.

Workflow · json
"liveness": { "enabled": true, "challenges": 3, "max_attempts": 3 }
KeyDefaultMeaning
challenges3How many random challenges to issue (1 to 4).
max_attempts3Attempts 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.

Four challenges, measured against the centre frame.
ChallengeMeasured asMust reach
turn_leftYaw change toward the subject's left15°
turn_rightYaw change toward the subject's right15°
smileMouth width relative to eye distance+12%
move_closerFace width relative to image width+25%
all framesSFace cosine to the centre face0.5
sequenceFirst to last frame timestamp1.5 s

Reasons and warnings

Exact codes, as they appear in the check's data and warnings, so you can branch on them.

Liveness codes
CodeOutcomeWhen
out_of_orderattempt failsFrames did not arrive as centre then each issued challenge, or timestamps did not increase.
too_fastattempt failsThe whole sequence spanned less than 1.5 seconds.
multiple_facesattempt failsA second face at least half the width of the main one appeared.
face_changedattempt failsA frame's face fell below 0.5 cosine to the centre face.
challenge_failedattempt failsA movement did not reach its threshold.
frames_identicalattempt failsTwo differently labelled frames are near pixel-identical: a still image replayed.
liveness_unavailablereviewFace 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.