Skip to main content

Liveness Detection

Confirm that a live human — not a printed photo, video replay, mask, or deepfake — is in front of the camera. AfriRoute offers two modes: passive liveness (no user action, single selfie) and active liveness (the user performs a challenge such as blinking or turning their head).

🚀 Quick Start​

curl -X POST https://api.afriroute.ai/api/v1/identity/liveness \
-H "Authorization: Bearer $AFRIROUTE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image": "<base64-selfie>",
"method": "passive"
}'

📡 Endpoint​

Check Liveness​

POST /v1/identity/liveness

Parameters​

FieldTypeRequiredDescription
imagestringConditionalBase64 selfie — required for passive method
videostringConditionalBase64 video — required for active method
methodstringYespassive or active
challengestringNoFor active: blink, smile, turn_left, turn_right, nod
challenge_responsestringNoToken issued for the active challenge being answered

💻 Code Samples​

Node.js — passive
const fs = require('fs');
const res = await fetch('https://api.afriroute.ai/api/v1/identity/liveness', {
method: 'POST',
headers: { 'Authorization': 'Bearer $AFRIROUTE_API_KEY', 'Content-Type': 'application/json' },
body: JSON.stringify({
image: fs.readFileSync('selfie.jpg', 'base64'),
method: 'passive'
})
});
const data = await res.json();
console.log(`liveness=${data.liveness_passed} confidence=${data.confidence}`);
Python — active challenge
import base64, requests

with open('liveness-video.mp4', 'rb') as f:
video = base64.b64encode(f.read()).decode()

res = requests.post(
'https://api.afriroute.ai/api/v1/identity/liveness',
headers={'Authorization': 'Bearer $AFRIROUTE_API_KEY'},
json={'video': video, 'method': 'active', 'challenge': 'blink'}
)
print(res.json()['liveness_passed'])

📊 Response​

{
"liveness_passed": true,
"confidence": 96.5,
"method": "passive",
"checks": {
"real_person": true,
"screen_detection": false,
"photo_detection": false,
"mask_detection": false,
"deepfake_detection": false,
"depth_analysis": "passed"
},
"quality_score": 94.2
}

🔍 Choosing a Method​

PassiveActive
User actionNonePerforms a challenge
InputSingle selfieShort video
FrictionLowestSlight
SecurityHighHighest
Best forQuick sign-ups, re-authenticationHigh-value KYC, account recovery

💡 Best Practices​

  • Issue active challenges randomly so attackers cannot pre-record a response.
  • Bind liveness to the same session as your face match to prevent injection of an unrelated live frame.
  • Run liveness server-side on the raw capture — never trust a client-asserted "live" flag.
  • Re-prompt on quality_score below 80 rather than rejecting outright.
  • Combine with face matching so a live face is also the correct person.

⚠️ Error Handling​

CodeHTTPDescription
NO_FACE_DETECTED422No face present in the capture
LIVENESS_FAILED422Presentation attack detected
CHALLENGE_MISMATCH422Active challenge response did not match the requested action
MEDIA_TOO_LARGE413Uploaded image or video exceeds size limit

See the error code reference for the full list.


Last Updated: May 2026 | Need help? [email protected]