Skip to content

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.

kycverify · productface_match
default match threshold (SFace's published cosine)
0.363
default review threshold
0.30
selfie against one reference portrait
1:1
SFace cosine · 0.363

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 as face_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

Runs in your browser
Evidence available
Reference portrait
0.612

1.0 is the same image. Genuine pairs from a selfie and a document photo usually sit well below that.

review 0.300match 0.363
0.363

At or above: passed. SFace's published cosine is 0.363.

0.300

Below: failed. Between the two: review. Never above threshold.

Passed: the faces match

The check passes; the session moves on to the other background checks.
face_match check
{
  "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. 1

    Embed

    The document portrait and the selfie are each embedded into an L2-normalised SFace vector when they are captured.

  2. 2

    Compare

    At submit, the cosine similarity of the two vectors is computed and compared with the workflow's thresholds.

  3. 3

    Record

    A face_match check stores the similarity, both thresholds and which reference was used.

Configuration

The workflow keys and their defaults.

Workflow · json
"face_match": { "enabled": true, "threshold": 0.363, "review_threshold": 0.30 }
KeyDefaultMeaning
threshold0.363Cosine at or above which the faces match.
review_threshold0.30Below this the check fails; between the two it goes to review.

Reference

Three outcomes, plus two honest gaps.

Three outcomes, plus two honest gaps.
SimilarityStatusReason
at or above threshold (0.363)passed-
between review_threshold (0.30) and thresholdreviewface_match_weak
below review_thresholdfailedface_match_failed
no usable selfie facereviewface_match_no_selfie
no document or Aadhaar portraitreviewface_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

face_match check · json
{
  "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.jpg

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