Skip to content

Conversation

@mehmet-yoti
Copy link
Contributor

Static Liveness Check Implementation

Overview

This implementation adds support for Static Liveness Check to the Yoti Python SDK, enabling identity verification using a single static image instead of the ZOOM liveness method which requires multiple frames and facemap data.

Features Added

1. Session Creation (Request Side)

Create STATIC Liveness Check

from yoti_python_sdk.doc_scan import RequestedLivenessCheckBuilder

# Build a STATIC liveness check
liveness_check = (
    RequestedLivenessCheckBuilder()
    .for_static_liveness()
    .with_max_retries(3)
    .with_manual_check_never()
    .build()
)

Generated JSON:

{
  "type": "LIVENESS",
  "config": {
    "liveness_type": "STATIC",
    "manual_check": "NEVER",
    "max_retries": 3
  }
}

2. Session Retrieval (Response Side)

Access STATIC Liveness Resources

from yoti_python_sdk.doc_scan import DocScanClient

client = DocScanClient(sdk_id, key_file_path)
session_result = client.get_session(session_id)

# Get all STATIC liveness resources
static_resources = session_result.resources.static_liveness_resources

for resource in static_resources:
    print(f"Resource ID: {resource.id}")
    print(f"Liveness Type: {resource.liveness_type}")
    
    # Access the image and media
    if resource.image and resource.image.media:
        media_id = resource.image.media.id
        media_type = resource.image.media.type
        created = resource.image.media.created
        
        print(f"Media ID: {media_id}")
        print(f"Media Type: {media_type}")

3. Media Content Retrieval

Download STATIC Liveness Image

# Get the first STATIC liveness resource
static_liveness = session_result.resources.static_liveness_resources[0]

# Extract media ID
media_id = static_liveness.image.media.id

# Retrieve the actual image content
media_content = client.get_media_content(session_id, media_id)

# Access the image bytes and MIME type
image_bytes = media_content.content
mime_type = media_content.mime_type  # e.g., "image/jpeg" or "image/png"

# Save to file
with open(f"liveness_image.{mime_type.split('/')[-1]}", "wb") as f:
    f.write(image_bytes)

Run Tests

# Run STATIC liveness tests only
pytest yoti_python_sdk/tests/doc_scan/session/create/check/test_liveness_check.py -v
pytest yoti_python_sdk/tests/doc_scan/session/retrieve/test_static_liveness_resource.py -v

# Run all doc_scan tests
pytest yoti_python_sdk/tests/doc_scan/ -v

Example Application

The Flask example application (examples/doc_scan/) now displays Static Liveness resources on the success page:

  • Shows resource ID and liveness type
  • Displays the static liveness image
  • Provides media ID for reference
  • Uses collapsible accordion UI similar to ZOOM liveness

Backward Compatibility

Fully backward compatible - All existing code using ZOOM liveness continues to work without any changes:

# Existing ZOOM liveness code still works
zoom_check = RequestedLivenessCheckBuilder().for_zoom_liveness().build()
zoom_resources = session_result.resources.zoom_liveness_resources

# New STATIC liveness code
static_check = RequestedLivenessCheckBuilder().for_static_liveness().build()
static_resources = session_result.resources.static_liveness_resources

Acceptance Criteria

All three acceptance criteria have been met:

  1. Add support for requesting a liveness check type STATIC

    • Implemented via for_static_liveness() builder method
    • Supports manual_check parameter (defaults to "NEVER")
  2. Add support for retrieving the updated liveness check response

    • Created StaticLivenessResourceResponse class
    • Added static_liveness_resources filter property
    • Parses image and media objects correctly
  3. Ensure that the SDKs support retrieving the media for the STATIC liveness check

    • Media ID accessible via resource.image.media.id
    • Existing get_media_content() method works seamlessly
    • Example application displays the image

For Existing Implementations

No changes required! Your existing ZOOM liveness code will continue to work. You can optionally add STATIC liveness support:

# Add STATIC liveness alongside existing ZOOM liveness
session_spec = (
    SessionSpecBuilder()
    .with_requested_check(
        RequestedLivenessCheckBuilder()
        .for_zoom_liveness()  # Existing
        .with_max_retries(1)
        .build()
    )
    .with_requested_check(
        RequestedLivenessCheckBuilder()
        .for_static_liveness()  # New
        .with_max_retries(3)
        .with_manual_check_never()
        .build()
    )
    # ... other configuration
    .build()
)

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for Static Liveness Check functionality to the Yoti Python SDK, enabling identity verification using a single static image instead of the existing ZOOM liveness method that requires multiple frames and facemap data.

Key Changes

  • Added StaticLivenessResourceResponse and ImageResponse classes to handle static liveness resource retrieval
  • Extended RequestedLivenessCheckBuilder with for_static_liveness() and with_manual_check_never() methods for session creation
  • Updated ResourceContainer to parse and filter static liveness resources alongside existing ZOOM resources

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
yoti_python_sdk/doc_scan/constants.py Added STATIC constant for the new liveness type
yoti_python_sdk/doc_scan/session/create/check/liveness.py Extended configuration and builder to support STATIC liveness type with optional manual_check parameter
yoti_python_sdk/doc_scan/session/retrieve/static_liveness_resource_response.py New class to represent static liveness resources with image data
yoti_python_sdk/doc_scan/session/retrieve/image_response.py New class to wrap image data containing media information for static liveness
yoti_python_sdk/doc_scan/session/retrieve/resource_container.py Updated to parse STATIC type and added filter property for static liveness resources
yoti_python_sdk/tests/doc_scan/session/create/check/test_liveness_check.py Added comprehensive tests for static liveness check creation and JSON serialization
yoti_python_sdk/tests/doc_scan/session/retrieve/test_static_liveness_resource.py New test file covering static liveness resource parsing and media ID retrieval
examples/doc_scan/templates/success.html Added UI section to display static liveness resources with collapsible accordion layout matching ZOOM liveness pattern
Comments suppressed due to low confidence (2)

yoti_python_sdk/doc_scan/session/retrieve/static_liveness_resource_response.py:4

  • Import of 'ResourceResponse' is not used.
from .resource_response import ResourceResponse

yoti_python_sdk/tests/doc_scan/session/retrieve/test_static_liveness_resource.py:2

  • Import of 'json' is not used.
import json

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@nikhilPank nikhilPank left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and it works locally.
There are a few cleanup recommendations from Copilot which could be implemented

Copy link

Copilot AI commented Nov 27, 2025

@mehmet-yoti I've opened a new pull request, #426, to work on those changes. Once the pull request is ready, I'll request review from you.

@sonarqubecloud
Copy link

@mehmet-yoti mehmet-yoti merged commit d1d8e58 into development Dec 1, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants