Start View
FaceLivenessDetector contains an initial (start) view with instructions and information about the Face Liveness check for the end user. By default, the start view is shown before the Face Liveness check. The start view can be disabled, allowing you to provide your own start view before FaceLivenessDetector is displayed in the app:
<FaceLivenessDetector
sessionId={createLivenessApiData.sessionId}
region='us-east-1'
onAnalysisCompleteDetection={onAnalysisCompleteDetection}
disableInstructionScreen={true}
/>
Internationalization (I18n)
The text in FaceLivenessDetector is defined as string resources in the component's displayText.ts file. These values can be translated/overwritten by following the example below:
import React from 'react';
import { FaceLivenessDetector } from '@aws-amplify/ui-react-liveness';
import { ToggleButtonGroup, ToggleButton } from '@aws-amplify/ui-react';
const dictionary = {
// use default strings for english
en: null,
es: {
photosensitivyWarningHeadingText: 'Advertencia de fotosensibilidad',
photosensitivyWarningBodyText:
'Esta verificación muestra luces de colores. Tenga cuidado si es fotosensible.',
goodFitCaptionText: 'Buen ajuste',
tooFarCaptionText: 'Demasiado lejos',
hintCenterFaceText: 'Centra tu cara',
startScreenBeginCheckText: 'Comenzar a verificar',
},
};
export function Customizationi18n() {
const [language, setLanguage] = React.useState<string>('en');
const [showLiveness, setShowLiveness] = React.useState(false);
React.useEffect(() => {
setShowLiveness(true);
}, []);
return (
<>
<ToggleButtonGroup
value={language}
isExclusive
onChange={(value) => setLanguage(value)}
>
<ToggleButton value="en">En</ToggleButton>
<ToggleButton value="es">Es</ToggleButton>
</ToggleButtonGroup>
{showLiveness && (
<FaceLivenessDetector
sessionId={'sessionId'}
region="us-east-1"
onAnalysisComplete={async () => {}}
displayText={dictionary[language]}
/>
)}
</>
);
}
Theming
CSS styles
You can customize FaceLivenessDetector's default style by using CSS variables.
The example below uses a <style>
tag to change the default colors to a dark theme:
[data-amplify-theme] {
--amplify-colors-background-primary: var(--amplify-colors-neutral-90);
--amplify-colors-background-secondary: var(--amplify-colors-neutral-100);
--amplify-colors-primary-10: var(--amplify-colors-teal-100);
--amplify-colors-primary-80: var(--amplify-colors-teal-40);
--amplify-colors-primary-90: var(--amplify-colors-teal-20);
--amplify-colors-primary-100: var(--amplify-colors-teal-10);
}
Theme Provider Theme
You can update the style of FaceLivenessDetector
by using the ThemeProvider theme object. To do this, you must surround FaceLivenessDetector
in the ThemeProvider
.
Then create a theme object, with all your font and color updates. Feel free to use design tokens, as a way of designing your theme further.
Below is an example of changing the default colors to a dark theme. You can also access the default dark mode override for the Amplify Theme Provider here.
import React from 'react';
import { FaceLivenessDetector } from '@aws-amplify/ui-react-liveness';
import { Theme, ThemeProvider, useTheme } from '@aws-amplify/ui-react';
export function CustomizationTheme() {
const [showLiveness, setShowLiveness] = React.useState(false);
React.useEffect(() => {
setShowLiveness(true);
}, []);
const { tokens } = useTheme();
const theme: Theme = {
name: 'Face Liveness Example Theme',
tokens: {
colors: {
background: {
primary: {
value: tokens.colors.neutral['90'].value,
},
secondary: {
value: tokens.colors.neutral['100'].value,
},
},
font: {
primary: {
value: tokens.colors.white.value,
},
},
brand: {
primary: {
'10': tokens.colors.teal['100'],
'80': tokens.colors.teal['40'],
'90': tokens.colors.teal['20'],
'100': tokens.colors.teal['10'],
},
},
},
},
};
return (
<ThemeProvider theme={theme}>
{showLiveness && (
<FaceLivenessDetector
sessionId={'sessionId'}
region={'us-east-1'}
onAnalysisComplete={async () => {}}
/>
)}
</ThemeProvider>
);
}
Components
FaceLivenessDetector allows overriding some UI components using the components
prop.
The following code snippet demonstrates how to pass in custom HTML rendering functions:
- Custom Photo Sensitivity Warning
- Custom Error View
- The children prop in ErrorView contains a default error component based on the LivenessError, you can use our default rendered components or render your own error message
import React from 'react';
import { FaceLivenessDetector } from '@aws-amplify/ui-react-liveness';
import { View, Heading, Alert } from '@aws-amplify/ui-react';
export function CustomizationComponents() {
const [showLiveness, setShowLiveness] = React.useState(false);
React.useEffect(() => {
setShowLiveness(true);
}, []);
return showLiveness ? (
<FaceLivenessDetector
sessionId={'sessionId'}
region={'us-east-1'}
onAnalysisComplete={async () => {}}
components={{
PhotosensitiveWarning: (): JSX.Element => {
return (
<Alert
variation="warning"
isDismissible={false}
hasIcon={true}
heading="Caution"
>
This check displays colored lights. Use caution if you are
photosensitive.
</Alert>
);
},
ErrorView: ({ children }) => {
return (
<View flex="1" backgroundColor="white">
<Heading color="black">My Custom Error View</Heading>
{children}
</View>
);
},
}}
/>
) : null;
}
Error View Example
The following code snippet demonstrates using a more customized error view which does not utilize the children component and instead renders your own full modal.
import React, { useCallback, useState } from 'react';
import { FaceLivenessDetector } from '@aws-amplify/ui-react-liveness';
import { Button, Flex, Heading, Text } from '@aws-amplify/ui-react';
export function CustomizationComponentsErrorView() {
const [error, setError] = useState(undefined);
const [showLiveness, setShowLiveness] = React.useState(false);
React.useEffect(() => {
setShowLiveness(true);
}, []);
const CustomError = useCallback(() => {
return (
<Flex
justifyContent="center"
alignItems="center"
width="100%"
height="100%"
>
<Flex
backgroundColor="white"
direction="column"
justifyContent="center"
padding="32px"
>
<Heading color="black">{error?.state}</Heading>
<Text>{error?.error.message}</Text>
<Button>Try again?</Button>
</Flex>
</Flex>
);
}, [error]);
return showLiveness ? (
<FaceLivenessDetector
sessionId="sessionId"
region="us-east-1"
onAnalysisComplete={async () => {}}
onError={setError}
components={{
ErrorView: CustomError,
}}
/>
) : null;
}
System Clock Offset
The systemClockOffset
can optionally be passed to the FaceLivenessDetectorCore
config, where it will be added as an offset in milliseconds to the AWS server time. This can be useful when the user's device time is inaccurate or when the user is frequently switching time zones. An example of calculating the offset and passing it to the FaceLivenessDetectorCore
is shown below:
import React from 'react';
import { FaceLivenessDetectorCore } from '@aws-amplify/ui-react-liveness';
function MyComponent() {
const [createLivenessApiData, setCreateLivenessApiData] = React.useState(null);
/*
* 1. Check whether the difference between server time and device time is
* greater than or equal to 5 minutes, and if so, return the offset in milliseconds.
* This logic should be adjusted based on the server response and use case
*/
const getSystemClockOffset = (serverTime: number) => {
const maxSupportedClockSkew = 5 * 60 * 1000; // 5 minutes
const deviceTime = Date.now();
const delta = serverTime ? serverTime - deviceTime : 0;
return Math.abs(delta) >= maxSupportedClockSkew ? delta : undefined;
}
React.useEffect(() => {
/*
* Replace with your own API call to create a session
*/
const response = await fetch(`/api/createSession`);
const body = await response.json(); // { sessionId: 'mockSessionId' }
/*
* Replace serverTime with the actual server date,
* which can be retrieved from the response headers or your custom backend.
*/
const serverTime = response.headers['date']
const systemClockOffset = getSystemClockOffset(serverTime)
setCreateLivenessApiData({body, systemClockOffset});
}, []);
return (
<div>
<FaceLivenessDetectorCore
sessionId={createLivenessApiData.sessionId}
region={'us-east-1'}
/*
* 2. Pass systemClockOffset to the config
*/
config={{
systemClockOffset={createLivenessApiData.systemClockOffset}
}}
/>
</div>
);
}
Custom CDN
FaceLivenessDetector allows overriding the default hosted CDN and providing your own. The CDN files are used by the TensorFlow library to load in files at runtime. You can host your own CDN by following the instructions below.
Learn more about the differences between the three different .wasm
files in this TensorFlow blog post.
- Download the TFJS wasm and blazeface files for the corresponding version of
@aws-amplify/ui-react-liveness
.- Download wasm files for tfjs here:
- <= v2.x
- https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@3.11.0/dist/tfjs-backend-wasm.wasm
- https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@3.11.0/dist/tfjs-backend-wasm-simd.wasm
- https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@3.11.0/dist/tfjs-backend-wasm-threaded-simd.wasm
- v3.x
- https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@4.11.0/dist/tfjs-backend-wasm.wasm
- https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@4.11.0/dist/tfjs-backend-wasm-simd.wasm
- https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@4.11.0/dist/tfjs-backend-wasm-threaded-simd.wasm
- <= v2.x
- Download and unzip the tar file. It should contain a
model.json
file and agroup1-shard1of1.bin
file.
- Download wasm files for tfjs here:
- Host all files alongside your JS files on your own server
- Update FaceLivenessDetector code:
import React from 'react';
import { FaceLivenessDetector } from '@aws-amplify/ui-react-liveness';
export function CustomizationCdn() {
const [showLiveness, setShowLiveness] = React.useState(false);
React.useEffect(() => {
setShowLiveness(true);
}, []);
return showLiveness ? (
<FaceLivenessDetector
sessionId={'sessionId'}
region="us-east-1"
onAnalysisComplete={async () => {}}
config={{
binaryPath: 'http://example.com/path/to/your/wasm/files/',
faceModelUrl:
'http://example.com/path/to/your/blazeface/file/model.json',
}}
/>
) : null;
}
binaryPath
must be a path to a folder with .wasm
files. faceModelUrl
must point to the model.json
file and will also expect the group1-shard1of1.bin
file to be colocated in the same path.
Best Practices
- The get ready screen has been optimized for increasing the end user's success rate and we strongly discourage making any changes to that screen.
- We do not recommend modifying the countdown time, face fit timeout, and oval size, as they affect the security and accuracy of the Face Liveness check.