Identity · Face match
The person on camera is the person on the card.
The best liveness frame is compared with the portrait from the document, or with the photo inside a signed Aadhaar artefact. The similarity is kept as evidence, with the thresholds that were applied.
- default match threshold (SFace's published cosine)
- 0.363
- default review threshold
- 0.30
- selfie against one reference portrait
- 1:1
What it checks
Face match, check by check.
Each rule below is what the engine actually runs. The result is written as a face_match check with its score and warnings.
Reference portrait
The document portrait is used when one was found; otherwise the photo embedded in the Aadhaar Secure QR or Offline e-KYC XML.
Three outcomes
At or above the match threshold the check passes. Between the review and match thresholds it goes to review as
weak_face_match. Below, it fails asface_mismatch.Missing faces are explicit
No usable selfie or no reference portrait sends the session to review with the reason, rather than passing silently.
Try it
Move the similarity, watch the outcome.
Two thresholds make three outcomes. Drag the similarity across them, tighten or relax the workflow, and see the check the engine would write, including when a face is missing.
- 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.
Face match: thresholds and outcomes
1.0 is the same image. Genuine pairs from a selfie and a document photo usually sit well below that.
At or above: passed. SFace's published cosine is 0.363.
Below: failed. Between the two: review. Never above threshold.
Passed: the faces match
{
"kind": "face_match",
"status": "passed",
"score": 0.612,
"data": {
"threshold": 0.363,
"review_threshold": 0.3,
"reference": "document",
"similarity": 0.612
},
"warnings": []
}Logic ported from backend/crates/kyc-api/src/engine/submit.rs. Nothing you type leaves this page.
How it works
What happens, in order.
- 1
Embed
The document portrait and the selfie are each embedded into an L2-normalised SFace vector when they are captured.
- 2
Compare
At submit, the cosine similarity of the two vectors is computed and compared with the workflow's thresholds.
- 3
Record
A
face_matchcheck stores the similarity, both thresholds and which reference was used.
Configuration
The workflow keys and their defaults.
"face_match": { "enabled": true, "threshold": 0.363, "review_threshold": 0.30 }| Key | Default | Meaning |
|---|---|---|
| threshold | 0.363 | Cosine at or above which the faces match. |
| review_threshold | 0.30 | Below this the check fails; between the two it goes to review. |
Reference
Three outcomes, plus two honest gaps.
| Similarity | Status | Reason |
|---|---|---|
| at or above threshold (0.363) | passed | - |
| between review_threshold (0.30) and threshold | review | face_match_weak |
| below review_threshold | failed | face_match_failed |
| no usable selfie face | review | face_match_no_selfie |
| no document or Aadhaar portrait | review | face_match_no_portrait |
API
Compare any two images.
POST /v1/checks/face-match takes image_a and image_b as multipart (JPEG, PNG or WebP) and returns the cosine, the decision at SFace's published threshold and how many faces each image held.
In a session
A passing face_match check
{
"kind": "face_match",
"status": "passed",
"score": 0.612,
"data": { "similarity": 0.612, "threshold": 0.363, "review_threshold": 0.3, "reference": "document" },
"warnings": []
}Compare any two images.
curl -X POST https://kycverify.me/api/v1/checks/face-match \
-H "x-api-key: $KYC_API_KEY" \
-F image_a=@selfie.jpg \
-F image_b=@passport-portrait.jpg200 OK
{
"similarity": 0.612,
"match": true,
"threshold": 0.363,
"faces": { "a": 1, "b": 1 }
}Limits
What it does not do.
Stated up front, so you can decide what to pair it with.
- Accuracy depends on the portrait: a small, worn or glare-covered document photo lowers similarity for genuine matches.
- KYCVerify publishes no accuracy rates for its face match. Tune the thresholds on your own traffic and review the borderline band.
FAQ
Face match: questions.
Can I compare two images outside a session?
Yes. POST /v1/checks/face-match takes image_a and image_b as multipart and returns the similarity, the match decision and the threshold.
Are face images sent anywhere?
Not to any third party. Detection and embedding run in-process on KYCVerify's engine. Embeddings are stored for duplicate detection and purged with the session.
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.