Reference image

The face match check can also be used to match or authenticate a user by using an existing facial image (selfie)—for example, one previously obtained from a liveness check.

This check uses AI to compare the portrait from the ID document with the reference facial image and returns a confidence score.

Configure face match

Before triggering the face match check, you have to create an IDV session configured with a Face Match check. Additionally, a reference face image has to be uploaded against which the ID document portrait will be compared.

const {
SessionSpecificationBuilder,
RequestedDocumentAuthenticityCheckBuilder,
RequestedTextExtractionTaskBuilder,
RequestedFaceMatchCheckBuilder,
SdkConfigBuilder
} = require('yoti');

// Face Match check
const faceMatchCheck = new RequestedFaceMatchCheckBuilder()
.withManualCheckFallback()
.build();

// Document authenticity check
const documentAuthenticityCheck = new RequestedDocumentAuthenticityCheckBuilder()
.withManualCheckFallback()
.build();

// Data Extraction
const textExtractionTask = new RequestedTextExtractionTaskBuilder()
.withManualCheckFallback()
.build();

// Configuration for the client SDK (Frontend)
const sdkConfig = new SdkConfigBuilder()
.withSuccessUrl('/success')
import com.yoti.api.client.docs.session.create.check.RequestedFaceMatchCheck;
import com.yoti.api.client.docs.session.create.check.RequestedDocumentAuthenticityCheck;
import com.yoti.api.client.docs.session.create.task.RequestedIdDocTextExtractionTask;
import com.yoti.api.client.docs.session.create.SdkConfig;
import com.yoti.api.client.docs.session.create.SessionSpec;

...
SessionSpec sessionSpec = SessionSpec.builder()
.withClientSessionTokenTtl(600)
.withResourcesTtl(90000)
.withUserTrackingId("some-user-tracking-id")
.withRequestedCheck(
RequestedFaceMatchCheck.builder()
.withManualCheckFallback()
.build()
)
.withRequestedCheck(
RequestedDocumentAuthenticityCheck.builder()
use Yoti\DocScan\Session\Create\Check\RequestedFaceMatchCheckBuilder;
use Yoti\DocScan\Session\Create\Check\RequestedDocumentAuthenticityCheckBuilder;
use Yoti\DocScan\Session\Create\Task\RequestedTextExtractionTaskBuilder;
use Yoti\DocScan\Session\Create\SdkConfigBuilder;
use Yoti\DocScan\Session\Create\SessionSpecificationBuilder;

$sessionSpec = (new SessionSpecificationBuilder())
->withClientSessionTokenTtl(600)
->withResourcesTtl(90000)
->withUserTrackingId('some-user-tracking-id')
->withRequestedCheck(
(new RequestedFaceMatchCheckBuilder())
->withManualCheckFallback()
->build()
)
->withRequestedCheck(
(new RequestedDocumentAuthenticityCheckBuilder())
->build()
Coming Soon
using Yoti.Auth;
using Yoti.Auth.DocScan;
using Yoti.Auth.DocScan.Session.Create;
using Yoti.Auth.DocScan.Session.Create.Check;
using Yoti.Auth.DocScan.Session.Create.Task;

...
var sessionSpec = new SessionSpecificationBuilder()
.WithClientSessionTokenTtl(600)
.WithResourcesTtl(90000)
.WithUserTrackingId("some-user-tracking-id")
.WithRequestedCheck(
new RequestedFaceMatchCheckBuilder()
.WithManualCheckFallback()
.Build()
)
.WithRequestedCheck(
new RequestedDocumentAuthenticityCheckBuilder()
.Build()
)
.WithRequestedTask(
new RequestedTextExtractionTaskBuilder()
.WithManualCheckFallback()
.Build()
package main

import (
"os"
"github.com/getyoti/yoti-go-sdk/v3/docscan"
"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create"
"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create/check"
"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create/task"
)

func buildSessionSpec() (sessionSpec *create.SessionSpecification, err error) {

var faceMatchCheck *check.RequestedFaceMatchCheck
faceMatchCheck, err = check.NewRequestedFaceMatchCheckBuilder().
WithManualCheckFallback().
Build()
if err != nil {
return nil, err
}
var documentAuthenticityCheck *check.RequestedDocumentAuthenticityCheck
documentAuthenticityCheck, err = check.NewRequestedDocumentAuthenticityCheckBuilder().

Initialise the Yoti client

The included DocScan/IDV Client includes several helper methods to interact with the Yoti's API. You can initialise the client using your unique SDK ID and PEM file.

const path = require('path');
const fs = require('fs');

const { IDVClient } = require('yoti');

const YOTI_CLIENT_SDK_ID = 'YOTI_CLIENT_SDK_ID';
const YOTI_PEM = fs.readFileSync(path.join(__dirname, '/path/to/pem'));

const idvClient = new IDVClient(YOTI_CLIENT_SDK_ID, YOTI_PEM);
import com.yoti.api.client.ClassPathKeySource;
import com.yoti.api.client.docs.DocScanClient;
import com.yoti.api.client.docs.DocScanException;

...
DocScanClient docScanClient = DocScanClient.builder()
.withClientSdkId("YOTI_CLIENT_SDK_ID")
.withKeyPairSource(ClassPathKeySource.fromClasspath("/path/to/pem"))
.build();
...
use Yoti\DocScan\DocScanClient;

$YOTI_CLIENT_SDK_ID = 'YOTI_CLIENT_SDK_ID';
$YOTI_PEM = '/path/to/pem';

$client = new DocScanClient($YOTI_CLIENT_SDK_ID, $YOTI_PEM);
Coming Soon
using System.IO;
using System.Net.Http;
using Yoti.Auth;
using Yoti.Auth.DocScan;

...
const string YOTI_CLIENT_SDK_ID = "YOTI_CLIENT_SDK_ID";
const string PEM_PATH = "/path/to/pem";

StreamReader privateKeyStream = System.IO.File.OpenText(PEM_PATH);
var key = CryptoEngine.LoadRsaKey(privateKeyStream);

var docScanClient = new DocScanClient(YOTI_CLIENT_SDK_ID, key, new HttpClient());
...
package main

import (
"os"

"github.com/getyoti/yoti-go-sdk/v3/docscan"
"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create"
"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create/check"
)

var (
sdkId string
key []byte
)

func main() {
var err error

sdkId = "YOTI_CLIENT_SDK_ID"
key, err = os.ReadFile("/path/to/pem")
if err != nil {
panic(err)
}

var client *docscan.Client
client, err = docscan.NewClient(sdkId, key)
if err != nil {
panic(err)
}
}

Create a session

You can use the createSession method from the above client to create a Yoti session. The session specification needs to be passed as an argument. After the session is successfully created, you will get a Session ID that can be used to retrieve the Session configuration.

let sessionId, sessionToken;

idvClient
.createSession(sessionSpec)
.then((session) => {
sessionId = session.getSessionId();
sessionToken = session.getClientSessionToken();
})
.catch((err) => {
console.log(err)
});

const sessionConfig = await idvClient.getSessionConfiguration(sessionId);
import com.yoti.api.client.docs.session.create.CreateSessionResult;
import com.yoti.api.client.docs.session.retrieve.configuration.SessionConfigurationResponse;

...
CreateSessionResult session = docScanClient.createSession(sessionSpec);

String sessionId = session.getSessionId();
String sessionToken = session.getClientSessionToken();

SessionConfigurationResponse sessionConfig = docScanClient.getSessionConfiguration(sessionId);
...
$session = $client->createSession($sessionSpec);

$sessionId = $session->getSessionId();
$sessionToken = $session->getClientSessionToken();

$sessionConfig = $client->getSessionConfiguration($sessionId);
Coming Soon
using Yoti.Auth.DocScan.Session.Retrieve.Configuration

...
CreateSessionResult session = docScanClient.CreateSession(sessionSpec);

string sessionId = session.SessionId;
string sessionToken = session.ClientSessionToken

SessionConfigurationResponse sessionConfig = docScanClient.GetSessionConfiguration(sessionId);
...
var createSessionResult *create.SessionResult
createSessionResult, err = client.CreateSession(sessionSpec)
if err != nil {
panic(err)
}

sessionId := createSessionResult.SessionID
clientSessionToken := createSessionResult.ClientSessionToken
sessionConfig, err := client.GetSessionConfiguration(sessionId)
if err != nil {
panic(err)
}

Create a Face Capture resource

Before uploading the reference face image, you have to create a Face capture resource. To do this, a Requirement ID from the Face Capture requirements needs to retrieved. This can then be used to create a face capture resource. If successful, you will receive a Resource Id.

const {
CreateFaceCaptureResourcePayloadBuilder,
UploadFaceCaptureImagePayloadBuilder,
} = require('yoti');

const resourceRequirements = sessionConfiguration.getCapture().getFaceCaptureResourceRequirements()[0];
const requirementId = resourceRequirements.getId();

const faceCapturePayload = new CreateFaceCaptureResourcePayloadBuilder()
.withRequirementId(requirementId)
.build();

const faceCaptureResource = await idvClient.createFaceCaptureResource(sessionId, faceCapturePayload);
const resourceId = faceCaptureResource.getId();
import com.yoti.api.client.docs.session.retrieve.configuration.SessionConfigurationResponse;
import com.yoti.api.client.docs.session.retrieve.configuration.capture;
import com.yoti.api.client.docs.session.retrieve.configuration.capture.facecapture;

import com.yoti.api.client.docs.session.create.facecapture.CreateFaceCaptureResourcePayload;
import com.yoti.api.client.docs.session.retrieve.CreateFaceCaptureResourceResponse;

...
RequiredFaceCaptureResourceResponse resourceRequirements = sessionConfig.getCapture().getFaceCaptureResourceRequirements().get(0);
String requirementId = resourceRequirements.getId();

CreateFaceCaptureResourcePayload faceCapturePayload = CreateFaceCaptureResourcePayload.builder()
.withRequirementId(requirementId)
.build();

CreateFaceCaptureResourceResponse faceCaptureResource = docScanClient.createFaceCaptureResource(sessionId, faceCapturePayload);
use Yoti\DocScan\Session\Retrieve\Configuration;
use Yoti\DocScan\Session\Retrieve\Configuration\Capture;
use Yoti\DocScan\Session\Retrieve\Configuration\Capture\CaptureResponse;

use Yoti\DocScan\Session\Create\FaceCapture;
use Yoti\DocScan\Session\Create\FaceCapture\CreateFaceCaptureResourcePayloadBuilder;
use Yoti\DocScan\Session\Retrieve\CreateFaceCaptureResourceResponse;

$resourceRequirements = $sessionConfig->getCapture()->getFaceCaptureResourceRequirements()[0];
$requirementId = $resourceRequirements->getId();

$faceCapturePayload = (new CreateFaceCaptureResourcePayloadBuilder())
->withRequirementId($requirementId)
->build();

$faceCaptureResource = $client->createFaceCaptureResource($sessionId, $faceCapturePayload);
$resourceId = $faceCaptureResource->getId();
Coming Soon
using Yoti.Auth.DocScan.Session.Create.FaceCapture
using Yoti.Auth.DocScan.Session.Create.FaceCapture.CreateFaceCaptureResourcePayloadBuilder
using Yoti.Auth.DocScan.Session.Retrieve.Configuration.Capture

...
RequiredFaceCaptureResourceResponse resourceRequirements = sessionConfiguration.Capture.GetFaceCaptureResourceRequirements()[0];
string requirementId = resourceRequirements.Id;

CreateFaceCaptureResourcePayload faceCapturePayload = new CreateFaceCaptureResourcePayloadBuilder()
.WithRequirementId(requirementId)
.Build();

CreateFaceCaptureResourceResponse faceCaptureResource = docScanClient.CreateFaceCaptureResource(sessionId, faceCapturePayload);
string resourceId = faceCaptureResource.Id;
...
import (
"os"

"github.com/getyoti/yoti-go-sdk/v3/docscan"
"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create"
"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create/facecapture"
)

func main() {
var err error

resourceRequirements := sessionConfig.GetCapture().GetFaceCaptureResourceRequirements()[0]
requirementId := resourceRequirements.GetID()

faceCapturePayload := facecapture.NewCreateFaceCaptureResourcePayload(requirementId)
faceCaptureResource, err := client.CreateFaceCaptureResource(sessionId, faceCapturePayload)
if err != nil {
panic(err)
}

resourceId := faceCaptureResource.GetID()
_ = resourceId // Use resourceId as needed

Upload a reference image

To do accurate face match, a reference facial image of the user is required. You have to get the contents of this image which can then be uploaded using the Doc Scan Client. You also have to pass in the Resource Id retrieved earlier

const fs = require('fs');

const imageBuffer = fs.readFileSync('path-to-selfie-jpeg');

const faceCaptureImagePayload = new UploadFaceCaptureImagePayloadBuilder()
.forJpegImage()
.withImageContents(imageBuffer)
.build();

await idvClient.uploadFaceCaptureImage(sessionId, resourceId, faceCaptureImagePayload);
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import com.yoti.api.client.docs.session.create.facecapture.UploadFaceCaptureImagePayload;

...
BufferedImage imageBuffer = ImageIO.read(new File("path-to-selfie-jpeg"));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(bImage, "jpg", bos);
byte[] data = bos.toByteArray();

UploadFaceCaptureImagePayload faceCaptureImagePayload = UploadFaceCaptureImagePayload.builder()
.forJpegImage()
.withImageContents(data)
.build();

docScanClient.uploadFaceCaptureImage(sessionId, resourceId, faceCaptureImagePayload);
...
use Yoti\Media\Image\Jpeg;
use Yoti\DocScan\Session\Create\FaceCapture\UploadFaceCaptureImagePayloadBuilder;

$imageData = file_get_contents('path-to-selfie-jpeg');

$faceCaptureImagePayload = (new UploadFaceCaptureImagePayloadBuilder())
->forJpegImage()
->withImageContents($imageData)
->build();

$client->uploadFaceCaptureImage($sessionId, $resourceId, $faceCaptureImagePayload);
Coming Soon
using System.IO;
using Yoti.Auth.DocScan.Session.Create.FaceCapture
using Yoti.Auth.DocScan.Session.Create.FaceCapture.UploadFaceCaptureImagePayloadBuilder

...
string imagePath = "path-to-selfie-jpeg";
byte[] imageData = File.ReadAllBytes(imagePath);

UploadFaceCaptureImagePayload faceCaptureImagePayload = new UploadFaceCaptureImagePayloadBuilder()
.ForJpegImage()
.WithImageContents(imageData)
.Build();

docScanClient.UploadFaceCaptureImage(sessionId, resourceId, faceCaptureImagePayload);
...
import (
"encoding/base64"
"os"

"github.com/getyoti/yoti-go-sdk/v3/docscan/session/create/facecapture"
)

func main() {
imgBytes, err := os.ReadFile("face.png")
if err != nil {
panic(err)
}
base64Str := base64.StdEncoding.EncodeToString(imgBytes)
}

addResource := client.AddFaceCaptureResourceToSession(sessionId, base64Str)

Client-side view

The next step is to load the Yoti client-side SDK. To do this, you need the below parameters generated with the session creation request above:

  • Session ID

  • Session Token

We then utilise these to construct a Web URL which loads the Yoti Client SDK. The URL is in the following format:

https://api.yoti.com/idverify/v1/web/index.html?sessionID=<sessionID>&sessionToken=<sessionToken>

Once the above URL launches in a web browser, it will take the user through the document capture flow. For more detailed steps, please refer to the Launch the user view page.


Retrieve results

Once a session has been completed, the associated checks' results and resources can be retrieved using the session ID. Each check would contain a recommendation and a breakdown. The resources however are not directly included in the results, but contain a media ID. This can be used to fetch the actual media resource.

Retrieve checks

idvClient.getSession(sessionId).then(sessionResult => {
const state = sessionResult.getState();
const faceMatchChecks = sessionResult.getFaceMatchChecks();
faceMatchChecks.map(check => {
const id = check.getId();
const state = check.getState();
const resourcesUsed = check.getResourcesUsed();
const report = check.getReport();
const recommendation = report.getRecommendation().getValue();
const breakdown = report.getBreakdown();
breakdown.forEach(function(breakdown) {
const subCheck = breakdown.getSubCheck();
const subCheckResult = breakdown.getResult();
});
})
}).catch(error => {
console.log(error);
GetSessionResult sessionResult = docScanClient.getSession(sessionId);
String state = sessionResult.getState();

List<? extends CheckResponse> faceMatchChecks = sessionResult.getFaceMatchChecks();

for (CheckResponse check: faceMatchChecks) {
String id = check.getId();
String state = check.getState();
List<String> resourcesUsed = check.getResourcesUsed();

ReportResponse report = check.getReport();
String recommendationValue = report.getRecommendation().getValue();
List<? extends BreakdownResponse> breakdown = report.getBreakdown();
for (BreakdownResponse breakdown: breakdown) {
String subCheck = breakdown.getSubCheck();
String subCheckResult = breakdown.getResult();
}
}
$sessionResult = $docScanClient->getSession($sessionId);
$state = $sessionResult->getState();

$faceMatchChecks = $sessionResult->getFaceMatchChecks();

foreach($faceMatchChecks as $check) {
$id = $check->getId();
$state = $check->getState();
$resourcesUsed = $check->getResourcesUsed();

$report = $check->getReport();
$recommendation = $report->getRecommendation()->getValue();
$breakdown = $report->getBreakdown();
foreach($breakdown as $breakdown) {
$subCheck = $breakdown->getSubCheck();
$subCheckResult = $breakdown->getResult();
}
}
Coming Soon
GetSessionResult sessionResult = docScanClient.GetSession(sessionId);
string state = sessionResult.State;

List<CheckResponse> faceMatchChecks = sessionResult.GetFaceMatchChecks();

foreach (CheckResponse check in faceMatchChecks)
{
string id = check.Id;
string state = check.State;
List<String> resourcesUsed = check.ResourcesUsed;

ReportResponse report = check.Report;
string recommendation = report.Recommendation.Value;
List<BreakdownResponse> breakdown = report.Breakdown;
foreach (BreakdownResponse breakdown in breakdown)
{
string subCheck = breakdown.SubCheck;
string subCheckResult = breakdown.Result;
}
}
var sessionResults *retrieve.GetSessionResult
sessionResults, err = client.GetSession(sessionId)
if err != nil {
panic(err)
}

state := sessionResults.State

faceMatchChecks := sessionResults.FaceMatchChecks()
for _, check := range faceMatchChecks {
id := check.GetID()
state := check.GetState()
resourcesUsed := check.GetResourcesUsed()

report := check.GetReport()
recommendation := report.GetRecommendation().GetValue()
breakdown := report.GetBreakdown()

for _, breakdown := range breakdown {
subCheck := breakdown.GetSubCheck()
subCheckResult := breakdown.GetResult()
}
}

Retrieve media

idvClient.getMediaContent(sessionId, mediaId).then(media => {
const buffer = media.getContent();
const mimeType = media.getMimeType();
const base64Content = media.getBase64Content();
// handle base64content or buffer
}).catch(error => {
console.log(error)
// handle error
})
Media media = docScanClient.getMediaContent(sessionId, mediaId);
$media = $docScanClient->getMediaContent($sessionId, $mediaId);
$mimeType = $media->getMimeType();
$base64Content = $media->getBase64Content();
Coming Soon
MediaValue media = docScanClient.GetMediaContent(sessionId, pageMediaId);
string mimeType = media->GetMIMEType();
string base64Content = $media->GetBase64URI();
media, err := client.GetMediaContent(sessionId, mediaID)
if err != nil {
panic(err)
}

mimeType := media.MIME()
content := media.Data()
base64URL := media.Base64URL()