Liveness Check: Verify Real Person from a Selfie Image
Send a selfie as Base64 and receive an instant liveness verdict — LIVE, SPOOF, or INCONCLUSIVE — alongside a confidence score and a plain-language breakdown of every signal that contributed to the decision.
The engine analyses each image through 8 independent signals: sharpness, eye geometry, head orientation, face framing, facial symmetry, skin micro-texture (LBP), EXIF camera metadata, and a frequency-domain GAN fingerprint detector. A spoof must defeat multiple signals simultaneously to cross the liveness threshold.
Designed for KYC onboarding, account recovery, and re-authentication flows. Works with standard mobile selfies — no specialised hardware required.
Printed photos
Screen displays
Deepfakes & GANs
Photo-of-a-photo
Endpoints
Request Payload
Send as Content-Type: application/json.
| Field | Description |
|---|---|
| image |
Base64 string · Required
The selfie to analyse. Accepts a raw Base64 string or a data-URL prefix
(data:image/jpeg;base64,...).
Supported formats: JPEG, PNG, WebP, BMP. Maximum size: 10 MB.
|
Response Fields
Top-level envelope
| Field | Type | Description |
|---|---|---|
| status | string | "success" or "error". Always check this first. |
| request_id | string | Unique identifier for this request. Format: lv_<16 hex chars>. Store this for audit trails and support queries. |
| timestamp | string | UTC response time in ISO 8601 format. |
| result | object | Detection result. Present on success; null on error. |
| error | object | Error detail. Present on failure; null on success. |
result object
| Field | Type | Description |
|---|---|---|
| verdict | string | "LIVE", "SPOOF", or "INCONCLUSIVE". See Verdicts below. |
| confidence | float | Aggregate liveness score ∈ [0, 1]. Higher = more confident the subject is live. |
| threshold | float | The decision threshold applied to produce the verdict. Default: 0.58. |
| face_detected | boolean | Whether a face was located in the submitted image. |
| signals | array | Array of 8 signal objects. Each describes one detection check. See Signals Reference below. |
signals array items
| Field | Type | Description |
|---|---|---|
| name | string | Machine-readable signal identifier (e.g. lbp_texture, fft_deepfake). |
| label | string | Human-readable name, safe for display in UIs and dashboards. |
| score | float | Signal score ∈ [0, 1]. Higher = more live-like for that check. |
| weight | float | This signal's contribution to the final confidence score. All 8 weights sum to 1.0. |
| passed | boolean | true if score ≥ 0.5. Convenience field — does not independently determine the verdict. |
| detail | string | Plain-language explanation of what was found. Safe to surface in logs, dashboards, and support tools. |
Verdicts
Confidence is at or above the threshold. The image is consistent with a real, live person.
→ Allow the user to proceed.
Confidence is more than 4 percentage points below the threshold. One or more signals indicate a spoof attempt.
→ Reject the attempt. Log request_id and confidence for your records.
Confidence is within ±4 percentage points of the threshold, or no face was detected. The engine cannot make a confident determination.
→ Prompt the user to retake the photo under better lighting or closer to the camera.
Confidence score ranges
| Range | Interpretation |
|---|---|
| 0.80 – 1.00 | Strong LIVE — multiple signals confirm a real face. |
| 0.62 – 0.79 | Moderate LIVE — most signals passed, minor issues present (e.g. compressed image). |
| 0.54 – 0.61 | Borderline — verdict is INCONCLUSIVE. Request a retake. |
| 0.35 – 0.53 | Weak — likely SPOOF but signals are mixed. |
| 0.00 – 0.34 | Strong SPOOF — multiple signals failed decisively. |
Signals Reference
Eight independent signals are computed per image. Each contributes a weighted sub-score to the final confidence value. No single signal determines the verdict — a spoof must defeat several simultaneously.
sharpness
Measures image sharpness using the Laplacian variance of the greyscale image. Printed photos and screen recaptures are often blurry or have lower-frequency detail than a live camera selfie.
| Score | Interpretation |
|---|---|
| 0.80 – 1.00 | Sharp, well-focused image |
| 0.50 – 0.79 | Moderate sharpness — typical for compressed mobile selfies |
| 0.00 – 0.49 | Soft or blurry — may indicate a recaptured image |
eye_aspect_ratio
Computes the Eye Aspect Ratio (EAR) for both eyes using 6 MediaPipe landmarks per eye — the ratio of eye height to eye width. Naturally open eyes have an EAR of approximately 0.25–0.35. Flat printed or screen-displayed images tend to produce slightly lower or less consistent EAR values due to 2D distortion.
| Score | Interpretation |
|---|---|
| 0.80 – 1.00 | Eyes naturally open |
| 0.50 – 0.79 | Partially open or slight occlusion |
| 0.00 – 0.49 | Eyes closed or EAR below minimum threshold |
head_pose
Extracts yaw, pitch, and roll from the 4×4 facial transformation matrix returned by MediaPipe. Extreme angles are more common when a phone or printout is held at an angle rather than a person facing the camera naturally.
| Score | Interpretation |
|---|---|
| 0.85 – 1.00 | Near-frontal, well-aligned |
| 0.50 – 0.84 | Slight rotation — within acceptable range |
| 0.00 – 0.49 | Significant rotation detected |
face_area_ratio
Measures what fraction of the image is occupied by the face bounding box. The optimal range for a selfie is 10–40%. Very small faces can indicate a photo-of-a-photo attack; faces filling the entire frame can indicate a tightly cropped spoof image.
| Condition | Score |
|---|---|
| Face < 4% of image area | Penalised |
| Face 4% – 80% of image area | Scored (optimal at 20%) |
| Face > 80% of image area | Fixed 0.50 |
facial_symmetry
Compares the positions of symmetric landmark pairs — eye corners, mouth corners, jawline edges — relative to the vertical midline of the face. Real faces are approximately symmetric. Warped, crumpled, or perspectively distorted spoof images show elevated asymmetry.
| Score | Interpretation |
|---|---|
| 0.80 – 1.00 | Highly symmetric — consistent with a genuine face |
| 0.50 – 0.79 | Mild asymmetry — within normal limits |
| 0.00 – 0.49 | Notable asymmetry detected |
lbp_texture
Highest weight
Extracts a 96×96 crop of the face region and computes a uniform Local Binary Pattern (LBP) histogram, which encodes the micro-texture of skin. Real skin has varied, non-uniform texture at the pixel level. Printed photos — even high-quality ones — and phone screen displays produce either flattened texture from halftone dot patterns or periodic pixel-grid structures.
Two sub-metrics are combined: Shannon entropy (real skin scores higher — more varied patterns) and dominant bin ratio (real skin stays below 0.60; spoofs typically exceed 0.65).
| Score | Interpretation |
|---|---|
| 0.80 – 1.00 | Skin texture matches a real face captured by a camera |
| 0.55 – 0.79 | Broadly consistent — some compression artefacts reduce texture variance |
| 0.35 – 0.54 | Partial texture uniformity — possible flat medium |
| 0.00 – 0.34 | Highly uniform or periodic texture — strong spoof indicator |
exif_metadata
Analyses EXIF metadata embedded in the raw image bytes before any re-encoding. Genuine camera photos carry hardware metadata — camera make/model, f-stop, ISO, shutter speed, focal length, GPS. Screenshots and images captured with screen-recording tools typically have no such metadata, or reveal their software origin in the EXIF Software tag.
| Condition | Score |
|---|---|
| No EXIF found | 0.50 (neutral) |
| EXIF present, no camera hardware tags | 0.55 |
| Camera make / model confirmed | 0.75 |
| Camera + optical parameters present | up to 1.00 |
| Screen-capture or editing software detected | 0.10 |
Detected spoof keywords: screenshot · screen capture · snipping · obs · bandicam · photoshop · gimp · preview · snagit
fft_deepfake
New
Analyses the frequency domain of the face region to detect artefacts left by GAN-based image generators and face-swap models — StyleGAN, ProGAN, FaceSwap, DeepFaceLab, and similar tools. These artefacts are largely invisible to the human eye but are statistically distinct from natural camera images.
Three sub-metrics are combined into the final score:
| Score | Interpretation |
|---|---|
| 0.80 – 1.00 | Frequency spectrum consistent with a natural camera image — no GAN fingerprints |
| 0.60 – 0.79 | Broadly natural — minor anomalies may result from heavy compression |
| 0.40 – 0.59 | Moderate frequency anomalies — possible GAN-generated content or face-swap processing |
| 0.00 – 0.39 | Strong periodic artefacts and directional bias — consistent with GAN generation |
No additional dependencies — computed using NumPy FFT, which is included in the base installation.
Error Codes
| HTTP | Code | Cause & Resolution |
|---|---|---|
| 422 | INVALID_REQUEST | The image field is missing, blank, not valid base64, or exceeds 10 MB. |
| 200 | NO_FACE_DETECTED | No face found in the image. The subject may be too far away, heavily occluded, or the image may be too dark or low-resolution. |
| 200 | INFERENCE_ERROR | An unexpected failure occurred during analysis. Retry the request. If the issue persists, contact support with the request_id. |
| 500 | SERVER_ERROR | Unhandled server exception. Contact support and include the request_id if present in the response. |
Image Requirements
- Face should occupy 10–40% of the image area — standard selfie distance from a phone.
- Subject should face the camera roughly forward — head rotation under ±30° in any axis.
- Adequate, even lighting — avoid strong backlighting, shadows across the face, or heavy glare.
- Exactly one face per image — do not submit group photos or cropped identity documents.
- Do not apply filters, beauty effects, or heavy post-processing before submission.
Configuration
All thresholds are set in liveness_api/settings.py under LIVENESS_CONFIG. Changes take effect on server restart. Contact your account manager if you need threshold adjustments for your specific use case.
| Parameter | Default | Description |
|---|---|---|
| live_threshold | 0.58 | Confidence ≥ this → LIVE. Within ±0.04 → INCONCLUSIVE. |
| min_face_confidence | 0.60 | Minimum MediaPipe face detection confidence to proceed with analysis. |
| min_blur_variance | 40.0 | Laplacian variance floor. Reduce for environments where images are heavily compressed. |
| min_ear | 0.15 | Eye Aspect Ratio below this value is treated as closed eyes. |
| max_yaw_deg | 35.0 | Maximum tolerated head yaw before the pose score begins to decay. |
| max_pitch_deg | 30.0 | Maximum tolerated head pitch before the pose score begins to decay. |
| min_face_area_ratio | 0.04 | Face bounding-box area as a fraction of image area below this value is penalised. |
| max_asymmetry | 0.20 | Symmetry index above this value yields a facial symmetry score of 0. |
| lbp_dominant_bin_spoof_threshold | 0.60 | LBP dominant bin fraction above which skin texture is considered suspiciously uniform. |
| fft_kurtosis_max | 12.0 | Ring kurtosis ceiling. Real images ≈ 3; GAN images often exceed 6. |
| fft_hf_ratio_baseline | 0.65 | Expected high-frequency energy ratio for a natural compressed selfie. |
| fft_az_variance_max | 0.35 | Azimuthal variance above this indicates directional GAN convolution bias. |
Features & Benefits
8-Signal Ensemble
No single check decides the outcome. A spoof must simultaneously defeat sharpness, LBP texture, head pose, eye geometry, facial symmetry, face area, EXIF metadata, and the FFT deepfake detector to cross the liveness threshold.
Deepfake Detection
The FFT fingerprint signal specifically targets GAN-generated and face-swapped images — attack vectors that bypass traditional liveness checks based on sharpness or geometry alone.
Mobile-Optimised
Thresholds and signal weights are calibrated for compressed JPEG selfies from modern smartphones — designed to minimise false rejections of legitimate users while maintaining strong fraud resistance.
Fast & Lightweight
All 8 signals run synchronously in a single request. Typical response under 200 ms on a 2-vCPU instance. The FFT signal uses NumPy only — no additional model downloads or infrastructure required.
For high-security use cases such as financial onboarding or regulated KYC flows, we recommend combining this API with an active liveness challenge (blink or head-turn prompt) and a certified ISO/IEC 30107-3 anti-spoofing SDK. Contact your account manager to discuss enterprise options.