Amplify UI

Customization

Customize your FaceLivenessDetector

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:

The following example requires that headers with the Date are available in the response. The solution will need to be modified based on the call to your backend API.
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.

  1. Download the TFJS wasm and blazeface files for the corresponding version of @aws-amplify/ui-react-liveness.
  2. Host all files alongside your JS files on your own server
  3. 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

  1. 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.
  2. 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.

Amplify open source software, documentation and community are supported by Amazon Web Services.

© 2024 Amazon Web Services, Inc. and its affiliates. All rights reserved. View the site terms and privacy policy.

Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.