Edit

Share via


Tutorial: Detect liveness in faces

Learn how to integrate face liveness detection into your workflow using server-side logic and companion frontend client applications.

Tip

For general information about face liveness detection, see the conceptual guide.

In this tutorial, you’ll learn how to run a frontend application with an app server to perform liveness detection, optionally adding face verification, across various platforms and languages.

Important

The Face client SDKs for liveness are a gated feature. You must request access to the liveness feature by filling out the Face Recognition intake form. When your Azure subscription is granted access, you can download the Face liveness SDK.

Prerequisites

  • Azure subscription - Create one for free
  • Your Azure account must have a Cognitive Services Contributor role assigned in order for you to agree to the responsible AI terms and create a resource. To get this role assigned to your account, follow the steps in the Assign roles documentation, or contact your administrator.
  • Once you have your Azure subscription, create a Face resource in the Azure portal to get your key and endpoint. After it deploys, select Go to resource.
    • You need the key and endpoint from the resource you create to connect your application to the Face service.
  • Access to the gated artifacts required for the Azure AI Vision Face Client SDK for Mobile (IOS and Android) and Web.
  • Familiarity with the Face liveness detection feature. See the conceptual guide.

Tip

After you complete the prerequisites, you can try the iOS liveness experience from iOS App Store, the Android liveness experience from the Android Google Play Store and the Web liveness experience from Vision Studio. Moreover, you can also build and run a complete frontend sample (either on iOS, Android, or Web) from the Samples section.

Prepare the frontend application

We provide SDKs in multiple languages to simplify integration with your frontend application. Refer to the README for your chosen SDK below to integrate both the UI and required code.

Important

Each frontend SDK requires access to a gated asset to successfully compile. Instructions on how to set this up are mentioned below.

For Swift iOS:

For Kotlin/Java Android:

For JavaScript Web:

Once integrated into your frontend application, the SDK will start the camera, guide the user to adjust their position, compose the liveness payload, and send it to the Azure AI Face service for processing.

Monitor the repository’s Releases section for new SDK version updates and enable automated dependency update alerts—e.g., GitHub Dependabot (for GitHub repos) or Renovate (GitHub, GitLab, Bitbucket, Azure Repos).

Perform liveness detection

The high-level steps involved in liveness orchestration are illustrated below:

Diagram of the liveness workflow in Azure AI Face.

  1. The frontend application starts the liveness check and notifies the app server.

  2. The app server creates a new liveness session with Azure AI Face Service. The service creates a liveness-session and responds back with a session-authorization-token. More information regarding each request parameter involved in creating a liveness session is referenced in Liveness Create Session Operation.

    var endpoint = new Uri(System.Environment.GetEnvironmentVariable("FACE_ENDPOINT"));
    var key = new AzureKeyCredential(System.Environment.GetEnvironmentVariable("FACE_APIKEY"));
    
    var body = JsonSerializer.Serialize(new
    {
        livenessOperationMode = "PassiveActive",
        deviceCorrelationId = "723d6d03-ef33-40a8-9682-23a1feb7bccd",
        enableSessionImage = true
    });
    
    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    var response = await client.PostAsync(
        $"{endpoint}/face/v1.2/detectLiveness-sessions",
        new StringContent(body, Encoding.UTF8, "application/json"));
    
    response.EnsureSuccessStatusCode();
    
    using var doc  = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var root       = doc.RootElement;
    
    Console.WriteLine("Session created");
    Console.WriteLine($"sessionId : {root.GetProperty("sessionId").GetString()}");
    Console.WriteLine($"authToken : {root.GetProperty("authToken").GetString()}");
    

    An example of the response body:

    {
        "sessionId": "a6e7193e-b638-42e9-903f-eaf60d2b40a5",
        "authToken": "<session-authorization-token>",
        "status": "NotStarted",
        "modelVersion": "2025-05-20",
        "results": {
            "attempts": []
        }
    }
    
  3. The app server provides the session-authorization-token back to the frontend application.

  4. The frontend application uses the session-authorization-token to start the face-liveness-detector which will kick off the liveness flow.

        FaceLivenessDetector(
            sessionAuthorizationToken = FaceSessionToken.sessionToken,
            verifyImageFileContent = FaceSessionToken.sessionSetInClientVerifyImage,
            deviceCorrelationId = "null",
            onSuccess = viewModel::onSuccess,
            onError = viewModel::onError
        )
    
  5. The SDK then starts the camera, guides the user to position correctly, and then prepares the payload to call the liveness detection service endpoint.

  6. The SDK calls the Azure AI Vision Face service to perform the liveness detection. Once the service responds, the SDK notifies the frontend application that the liveness check has been completed. Note: the service response will not contain the liveness decision, and this will need to be queried from the app server.

  7. The frontend application relays the liveness check completion to the app server.

  8. The app server can now query for the liveness detection result from the Azure AI Vision Face service.

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    var response = await client.GetAsync(
        $"{endpoint}/face/v1.2/livenessSessions/{sessionId}/result");
    
    response.EnsureSuccessStatusCode();
    
    using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var root = doc.RootElement;
    var attempts = root.GetProperty("results").GetProperty("attempts");
    var latestAttempt = attempts[attempts.GetArrayLength() - 1];
    var attemptStatus = latestAttempt.GetProperty("attemptStatus").GetString();
    
    Console.WriteLine($"Session id: {root.GetProperty("sessionId").GetString()}");
    Console.WriteLine($"Session status: {root.GetProperty("status").GetString()}");
    Console.WriteLine($"Latest attempt status: {attemptStatus}");
    
    if (attemptStatus == "Succeeded")
        Console.WriteLine($"Liveness detection decision: {latestAttempt.GetProperty("result").GetProperty("livenessDecision").GetString()}");
    else
    {
        var error = latestAttempt.GetProperty("error");
        Console.WriteLine($"Error: {error.GetProperty("code").GetString()} - {error.GetProperty("message").GetString()}");
    }
    

    An example of the response body:

    {
        "sessionId": "b12e033e-bda7-4b83-a211-e721c661f30e",
        "authToken": "eyJhbGciOiJFUzI1NiIsIm",
        "status": "NotStarted",
        "modelVersion": "2024-11-15",
        "results": {
            "attempts": [
                {
                    "attemptId": 2,
                    "attemptStatus": "Succeeded",
                    "result": {
                    "livenessDecision": "realface",
                    "targets": {
                        "color": {
                        "faceRectangle": {
                                "top": 669,
                                "left": 203,
                                "width": 646,
                                "height": 724
                            }
                        }
                    },
                    "digest": "B0A803BB7B26F3C8F29CD36030F8E63ED3FAF955FEEF8E01C88AB8FD89CCF761",
                    "sessionImageId": "Ae3PVWlXAmVAnXgkAFt1QSjGUWONKzWiSr2iPh9p9G4I"
                    }
                },
                {
                    "attemptId": 1,
                    "attemptStatus": "Failed",
                    "error": {
                    "code": "FaceWithMaskDetected",
                    "message": "Mask detected on face image.",
                    "targets": {
                            "color": {
                            "faceRectangle": {
                                "top": 669,
                                "left": 203,
                                "width": 646,
                                "height": 724
                            }
                            }
                        }
                    }
                }
            ]
        }
    }
    
  9. The app server can delete the session once all session-results have been queried.

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    await client.DeleteAsync($"{endpoint}/face/v1.2/livenessSessions/{sessionId}");
    Console.WriteLine($"Session deleted: {sessionId}");
    

Perform liveness detection with face verification

Combining face verification with liveness detection enables biometric verification of a particular person of interest with an added guarantee that the person is physically present in the system.

Diagram of the liveness-with-face-verification workflow of Azure AI Face.

There are two parts to integrating liveness with verification:

Step 1 - Select a reference image

Follow the tips listed in the composition requirements for ID verification scenarios to ensure that your input images give the most accurate recognition results.

Step 2 - Set up the orchestration of liveness with verification.

The high-level steps involved in liveness with verification orchestration are illustrated below:

  1. Providing the verification reference image by either of the following two methods:

    • The app server provides the reference image when creating the liveness session. More information regarding each request parameter involved in creating a liveness session with verification is referenced in Liveness With Verify Create Session Operation.

      var endpoint = new Uri(System.Environment.GetEnvironmentVariable("FACE_ENDPOINT"));
      var key      = System.Environment.GetEnvironmentVariable("FACE_APIKEY");
      
      // Create the JSON part
      var jsonPart = new StringContent(
          JsonSerializer.Serialize(new
          {
              livenessOperationMode = "PassiveActive",
              deviceCorrelationId = "723d6d03-ef33-40a8-9682-23a1feb7bcc",
              enableSessionImage = true
          }),
          Encoding.UTF8,
          "application/json"
      );
      jsonPart.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
      {
          Name = "CreateLivenessWithVerifySessionRequest"
      };
      
      // Create the file part
      using var fileStream = File.OpenRead("test.png");
      var filePart = new StreamContent(fileStream);
      filePart.Headers.ContentType = new MediaTypeHeaderValue("image/png");
      filePart.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
      {
          Name = "VerifyImage",
          FileName = "test.png"
      };
      
      // Build multipart form data
      using var formData = new MultipartFormDataContent();
      formData.Add(jsonPart);
      formData.Add(filePart);
      
      using var client = new HttpClient();
      client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
      
      var response = await client.PostAsync($"{endpoint}/face/v1.2/createLivenessWithVerifySession", formData);
      response.EnsureSuccessStatusCode();
      
      using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
      var root = doc.RootElement;
      
      Console.WriteLine("Session created.");
      Console.WriteLine($"Session id: {root.GetProperty("sessionId").GetString()}");
      Console.WriteLine($"Auth token: {root.GetProperty("authToken").GetString()}");
      

      An example of the response body:

      {
          "sessionId": "3847ffd3-4657-4e6c-870c-8e20de52f567",
          "authToken": "<session-authorization-token>",
          "status": "NotStarted",
          "modelVersion": "2024-11-15",
          "results": {
              "attempts": [],
              "verifyReferences": [
              {
                  "referenceType": "image",
                  "faceRectangle": {
                  "top": 98,
                  "left": 131,
                  "width": 233,
                  "height": 300
                  },
                  "qualityForRecognition": "high"
              }
              ]
          }
      }
      
    • The frontend application provides the reference image when initializing the mobile SDKs. This scenario is not supported in the web solution.

          FaceLivenessDetector(
              sessionAuthorizationToken = FaceSessionToken.sessionToken,
              verifyImageFileContent = FaceSessionToken.sessionSetInClientVerifyImage,
              deviceCorrelationId = "null",
              onSuccess = viewModel::onSuccess,
              onError = viewModel::onError
          )
      
  2. The app server can now query for the verification result in addition to the liveness result.

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    var response = await client.GetAsync($"{endpoint}/face/v1.2/livenessSessions/{sessionId}/result");
    response.EnsureSuccessStatusCode();
    
    using var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
    var root = doc.RootElement;
    
    var attempts = root.GetProperty("results").GetProperty("attempts");
    var latestAttempt = attempts[attempts.GetArrayLength() - 1];
    var attemptStatus = latestAttempt.GetProperty("attemptStatus").GetString();
    
    Console.WriteLine($"Session id: {root.GetProperty("sessionId").GetString()}");
    Console.WriteLine($"Session status: {root.GetProperty("status").GetString()}");
    Console.WriteLine($"Latest attempt status: {attemptStatus}");
    
    if (attemptStatus == "Succeeded")
    {
        var decision = latestAttempt.GetProperty("result").GetProperty("livenessDecision").GetString();
        var verify   = latestAttempt.GetProperty("verifyResult");
        Console.WriteLine($"Liveness detection decision: {decision}");
        Console.WriteLine($"Verify isIdentical: {verify.GetProperty("isIdentical").GetBoolean()}");
        Console.WriteLine($"Verify matchConfidence: {verify.GetProperty("matchConfidence").GetDouble()}");
    }
    else
    {
        var err = latestAttempt.GetProperty("error");
        Console.WriteLine($"Error: {err.GetProperty("code").GetString()} - {err.GetProperty("message").GetString()}");
    }
    

    An example of the response body:

    {
        "sessionId": "b12e033e-bda7-4b83-a211-e721c661f30e",
        "authToken": "eyJhbGciOiJFUzI1NiIsIm",
        "status": "NotStarted",
        "modelVersion": "2024-11-15",
        "results": {
            "attempts": [
            {
                "attemptId": 2,
                "attemptStatus": "Succeeded",
                "result": {
                "livenessDecision": "realface",
                "targets": {
                    "color": {
                    "faceRectangle": {
                        "top": 669,
                        "left": 203,
                        "width": 646,
                        "height": 724
                    }
                    }
                },
                "verifyResult": {
                    "matchConfidence": 0.08871888,
                    "isIdentical": false
                },
                "digest": "B0A803BB7B26F3C8F29CD36030F8E63ED3FAF955FEEF8E01C88AB8FD89CCF761",
                "sessionImageId": "Ae3PVWlXAmVAnXgkAFt1QSjGUWONKzWiSr2iPh9p9G4I",
                "verifyImageHash": "43B7D8E8769533C3290DBD37A84D821B2C28CB4381DF9C6784DBC4AAF7E45018"
                }
            },
            {
                "attemptId": 1,
                "attemptStatus": "Failed",
                "error": {
                    "code": "FaceWithMaskDetected",
                    "message": "Mask detected on face image.",
                    "targets": {
                        "color": {
                        "faceRectangle": {
                                "top": 669,
                                "left": 203,
                                "width": 646,
                                "height": 724
                            }
                        }
                    }
                }
            }
            ],
            "verifyReferences": [
                {
                    "referenceType": "image",
                    "faceRectangle": {
                    "top": 316,
                    "left": 131,
                    "width": 498,
                    "height": 677
                    },
                    "qualityForRecognition": "high"
                }
            ]
            }
        }
    
  3. The app server can delete the session if you don't need its result anymore.

    using var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", key);
    
    await client.DeleteAsync($"{endpoint}/face/v1.2/livenessWithVerifySessions/{sessionId}");
    Console.WriteLine($"Liveness-with-Verify session deleted: {sessionId}");
    

Perform other face operations after liveness detection

Optionally, you can do further face operations after the liveness check, such as face analysis (to get face attributes, for example) and/or face identity operations.

  1. To enable this, you'll need to set the "enableSessionImage" parameter to "true" during the Session-Creation step.
  2. After the session completes, you can extract the "sessionImageId" from the Session-Get-Result step.
  3. You can now either download the session-image (referenced in Liveness Get Session Image Operation API), or provide the "sessionImageId" in the Detect from Session Image ID API operation to continue to perform other face analysis or face identity operations. For more information on these operations, see Face detection concepts and Face Recognition concepts.

Support options

In addition to using the main Azure AI services support options, you can also post your questions in the issues section of the SDK repo.

To learn how to integrate the liveness solution into your existing application, see the Azure AI Vision SDK reference.

To learn more about the features available to orchestrate the liveness solution, see the Session REST API reference.