FaceLivenessDetectorは、AWSが配布するReact向けパッケージ @aws-amplify/ui-react-liveness が提供するUIコンポーネントです。カメラの前にいるのが実在の人物かどうかを、短い自撮り動画からAmazon Rekognition側で判定します。最新版は3.6.8(2026年7月28日公開)。コンポーネントを置くだけならpropsは3つで足りますが、実装が止まるのはUIではなく、セッションの寿命・IAM権限・スコアのしきい値・SDKの更新義務です。この4点を軸に、端末要件やCSP、リージョンごとの単価まで、AWSの一次情報と手元で実行した検証結果で埋めていきます。
まとめ:セッションは使い捨て、判定はバックエンド、SDKは更新が義務
- セッションIDは発行から3分で失効し、1回のチェックでしか使えません。エラー時の再試行は必ず新しいIDを発行します。
- 生体判定のスコアはバックエンドで受け取り、クライアントへは合否だけを返します。これはAWS自身が推奨として明記している設計です。
- SDKには更新義務があります。新しいメジャー版の公開から120日を過ぎると、旧メジャー版からのリクエストは遮断される可能性があります。
- チャレンジ設定は2種類です。2025年7月3日に追加された
FaceMovementChallengeは光の点滅を省いて所要時間を3秒短縮しますが、精度はFaceMovementAndLightChallengeのほうが上です。 - Amplify Gen 1のCLI手順(
amplify init)で書かれた記事は2027年5月1日のEOLに向かっています。新規はGen 2で組みます。 - 東京リージョンの単価は50万回まで1回0.0195 USDで、バージニア北部の0.0150 USDより30%高くなります。
FaceLivenessDetectorが担う範囲と3つのAPIの呼び分け
CreateFaceLivenessSessionはバックエンド、StartFaceLivenessSessionはコンポーネント
Face Livenessは3つのAPIで動きます。CreateFaceLivenessSessionをあなたのバックエンドが呼んでセッションIDを取得し、StartFaceLivenessSessionはFaceLivenessDetectorコンポーネントがブラウザから直接呼び、GetFaceLivenessSessionResultsを再びバックエンドが呼んで結果を取ります。開発者ガイドはこの3段構えを明示していて、フロントエンドに渡してよい権限はStartFaceLivenessSessionだけです。
ここを取り違えると権限設計が崩れます。Cognito Identity PoolのロールにAmazonRekognitionFullAccessを付けてしまうと、ブラウザに配布される一時認証情報から信頼度スコアを直接読めるようになり、合否の判断材料がクライアント側に露出します。バックエンド側のIAMポリシーにはCreateFaceLivenessSessionとGetFaceLivenessSessionResultsの2つ、フロント側にはStartFaceLivenessSessionの1つ、と分けてください。
コンポーネントを使わず自前でストリーミングを実装する余地は無く、Amplifyの導入が前提になります。バックエンド定義の全体像はAWS AmplifyのGen 2解説にまとめてあります。
セッションIDの3分制限と使い捨て前提のリトライ設計
CreateFaceLivenessSessionが返すSessionIdは36文字固定のUUIDです。APIモデル上もminとmaxがどちらも36で、正規表現でハイフン区切りの形式が強制されています。開発者ガイドによれば、このIDは送出から3分で失効し、失効後はリファレンス画像も監査画像も取得できなくなります。同じIDを2回目のチェックに使うと、そのチェックは失敗します。
実装上の帰結ははっきりしています。onErrorが呼ばれたら、同じIDで再描画してはいけません。Amplify UIの公式ドキュメントも「エラー発生時はユーザーに再試行させる前に新しいセッションを作る必要がある」と書いています。ユーザーがカメラ許可を拒否して戻ってきた場合も同じです。セッション発行のエンドポイントは、UIの再試行ボタンから何度でも叩かれる前提で設計してください。
FaceMovementAndLightChallengeとFaceMovementChallengeの選び分け
チャレンジ設定は2種類あります。従来からあるFaceMovementAndLightChallengeは、顔を楕円に合わせたうえで画面に色の光を連続表示します。追加されたFaceMovementChallengeは光の点滅を省き、AWSの発表によればチェック時間が3秒短くなります。加えて前面カメラだけでなく背面カメラでも完了できます。発表は2025年7月3日ですが、開発者ガイドのバージョン表はこのチャレンジのv1.0.0のリリース日を2025年4月30日としており、公式内で日付が割れています。
| 観点 | FaceMovementAndLightChallenge | FaceMovementChallenge |
|---|---|---|
| 既定値 | FaceMovementAndLightChallenge | 明示指定が必要 |
| 色光の点滅 | あり | なし |
| 所要時間 | 基準 | 3秒短い |
| 使えるカメラ | 前面(背面可の明記なし) | 前面・背面 |
| 精度 | 最も高い | AndLightより低い |
精度を最優先するならFaceMovementAndLightChallengeです。開発者ガイドは「精度を最大化する設定として残る」と明記し、発表文も最高精度の設定として位置づけています。判断材料として挙げられているのは、想定する攻撃の種類と、許容できる誤受入率・誤拒否率の2つです。あわせて、IPベースの地理情報やワンタイムパスコードといった追加チェックを実装するよう求めており、これはチャレンジ種別を問わない要求です。
APIモデル上、ChallengePreferences[].Typeに指定できるのはFaceMovementAndLightChallengeとFaceMovementChallengeの2値だけです。ここは注意が必要で、開発者ガイドの本文にはFaceLivenessMovementAndLightChallengeという綴りが登場しますが、これは実在しません。botocoreのサービス定義を見ればenumは2値だけと確認できます。ドキュメントの文中表記ではなく、APIモデルの値をそのまま書いてください。
光の点滅そのものにも配慮が要ります。開発者ガイドのFAQは、色の変化がWCAG 2.1のガイドラインに沿っており、1秒あたり約2色という速度が「3色以下」という推奨に収まると説明しています。それでも光過敏の利用者は存在するため、AWSは代替の本人確認経路を用意するよう推奨しています。楕円の位置・形状・カウントダウン時間はいずれもカスタマイズできません。
Amplify Gen 2でのバックエンド構成とIAM権限の絞り込み
Gen 1のCLI手順に付いた2027年5月1日というEOL期限
amplify initから始まるAmplify Gen 1のCLI手順で書かれた解説は、Amplify UIの公式ドキュメントにもタブとして残っています。この手順自体はまだ動きますが、期限が切られました。Amplify Gen 1はメンテナンスモードに入っており、2026年5月1日以降は重大なバグ修正とセキュリティパッチのみ、2027年5月1日にEOLを迎えます。EOLの日付はGen 1ドキュメントの冒頭バナーに、2026年5月1日からの縮退はamplify-cliリポジトリのIssue #14881(2026年5月14日)に書かれています。
新規に組むならGen 2一択です。既存のGen 1プロジェクトに機能追加する場合でも、EOLまでの残り期間と移行コストを先に見積もっておくべきでしょう。移行ガイドとツールはAWSが用意しています。
Identity Poolに付与するのはStartFaceLivenessSessionだけ
Gen 2では、認証リソースを定義したうえでamplify/backend.tsにインラインポリシーを足します。Cognitoを使うといってもユーザーを移行する必要はありません。FaceLivenessDetectorは既定でCognito Identity Poolを使いますが、その用途はRekognitionへのリクエスト署名に限られます。Amazon Cognito側の設計を変えずに追加できるのはこのためです。
// amplify/backend.ts
import { defineBackend } from '@aws-amplify/backend';
import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { auth } from './auth/resource';
const backend = defineBackend({ auth });
const livenessStack = backend.createStack('liveness-stack');
const livenessPolicy = new Policy(livenessStack, 'LivenessPolicy', {
statements: [
new PolicyStatement({
actions: ['rekognition:StartFaceLivenessSession'],
resources: ['*'],
}),
],
});
backend.auth.resources.unauthenticatedUserIamRole.attachInlinePolicy(livenessPolicy); // 未ログインの利用者
backend.auth.resources.authenticatedUserIamRole.attachInlinePolicy(livenessPolicy); // ログイン済みの利用者
未ログイン状態でチェックを走らせるならunauthenticatedUserIamRole、ログイン後に走らせるならauthenticatedUserIamRoleに付けます。両方の経路がある画面では両方に付与します。前掲のとおりバックエンド側には別のロールが必要で、こちらはブラウザに配布されない実行環境に置いてください。
フロントエンド実装|必須propsとエラー時のセッション再発行
コンポーネントに必須のpropsはsessionId、region、onAnalysisCompleteの3つです。regionはCreateFaceLivenessSessionを呼んだリージョンと一致させます。Amplify.configure()を済ませてあることが前提です。以下は@aws-amplify/ui-react-liveness 3.6.8とReact 19の型定義に対してtsc --noEmitを通したコードです(終了コード0)。試しにregionを外すとTS2741で落ちるので、この3つが必須という点は型でも確認できます。
import { useCallback, useEffect, useRef, useState } from 'react';
import { FaceLivenessDetector } from '@aws-amplify/ui-react-liveness';
import { Loader, ThemeProvider } from '@aws-amplify/ui-react';
const REGION = 'ap-northeast-1';
export function LivenessCheck({ onVerified }: { onVerified: (ok: boolean) => void }) {
const [sessionId, setSessionId] = useState<string | null>(null);
const isHandlingError = useRef(false);
const createSession = useCallback(async () => {
const res = await fetch('/api/liveness/session', { method: 'POST' });
const { sessionId } = (await res.json()) as { sessionId: string };
setSessionId(sessionId);
}, []);
useEffect(() => {
void createSession();
}, [createSession]);
const handleAnalysisComplete = async () => {
// スコアではなく合否だけを返すエンドポイントを叩く
const res = await fetch(`/api/liveness/result?sessionId=${sessionId}`);
const { passed } = (await res.json()) as { passed: boolean };
onVerified(passed);
};
if (!sessionId) return <Loader />;
return (
<ThemeProvider>
<FaceLivenessDetector
sessionId={sessionId}
region={REGION}
onAnalysisComplete={handleAnalysisComplete}
onError={async () => {
// エラー要因が続くと再発行と再マウントが閉ループになる
if (isHandlingError.current) return;
isHandlingError.current = true;
setSessionId(null);
// セッションは使い捨て。再試行は必ず新しい sessionId で
await createSession();
isHandlingError.current = false;
}}
onUserCancel={() => onVerified(false)}
/>
</ThemeProvider>
);
}
onErrorの中で古いIDを捨てて再発行しつつ、isHandlingErrorで多重実行を止めている点が要点です。カメラ権限の拒否のようにエラー要因が続く状況では、再発行と再マウントが閉ループになります。公式サンプルも同じ位置にこのガードを置いています。onUserCancelは、既定のエラーモーダルで「Try Again」が押されたときにも呼ばれます。任意のpropsとしては、開始画面を省くdisableStartScreenと、カメラ指定やモデル配信元を上書きするconfigがあります。
React 19で使う場合、インストール時にERESOLVE overriding peer dependencyの警告が3件出ます。原因はいずれも@xstate/[email protected]で、このパッケージのpeerが^16.8.0 || ^17.0.0 || ^18.0.0までしか許容していません。@aws-amplify/ui-react-liveness自身の直接依存に加えて@aws-amplify/ui-reactと@aws-amplify/ui-react-coreからも入るため、同じ警告が3経路ぶん重複します。手元のクリーンなディレクトリでReact 19を入れて3件を実測しましたが、インストールは完了し型検査も通ります。CIで警告をエラー扱いにしている場合だけ対処が必要です。
バックエンドのしきい値判定とスコアを非公開にする設計
屋内80〜90、屋外50〜60というAWSの目安
Rekognitionが返すのは0〜100の信頼度スコアだけです。「生体か否か」をサービスが決めるわけではありません。AI Service Cardはこの点を明示していて、判定は顧客が設定するしきい値、人間の判断、またはその組み合わせの結果だとしています。
しきい値の目安も同じ資料に数字で出ています。オフィス照明のような安定した屋内環境では80〜90が適切とされ、直射日光下のように色光が顔に反射しにくい屋外では50〜60のほうがバランスが取れるとされています。真正ユーザーの通過率(TAR)となりすましの拒否率(TRR)は逆相関するため、片方だけを最大化する設定は成立しません。銀行口座の開設のようにセキュリティ要件が重い用途では高いしきい値を選び、そのぶん増える誤拒否を再試行の導線でカバーする、という順序で決めます。
boto3のクライアント側検証で弾けない値
バックエンド側は、セッション作成と結果取得の2関数だけで足ります。監査画像を返させたい場合はAuditImagesLimitを指定します。指定できるのは0から4で、既定は0です。
import boto3
client = boto3.client("rekognition", region_name="ap-northeast-1")
def create_session():
res = client.create_face_liveness_session(
Settings={
"AuditImagesLimit": 2,
"ChallengePreferences": [{"Type": "FaceMovementAndLightChallenge"}],
}
)
return res["SessionId"]
def is_live(session_id, threshold=80.0):
res = client.get_face_liveness_session_results(SessionId=session_id)
if res["Status"] != "SUCCEEDED":
return False, res["Status"], None
score = res["Confidence"]
return score >= threshold, res["Status"], score
このコードはbotocore.stub.Stubberでスタブ化したクライアントに対して実行し、SUCCEEDEDとEXPIREDの両方の分岐が意図どおり動くことを確認しています。ただし、手元で通ったからといってAPIが受け付けるとは限りません。botocore 1.42.97のパラメータ検証(botocore.validate.ParamValidatorにCreateFaceLivenessSessionのinput shapeを渡し、5ケースを流したもの)を単体で走らせると、次のようになりました。
$ python validate.py
docs-style FaceMovementChallenge: OK
no params at all: OK
wrong enum (typo from dev guide): OK
AuditImagesLimit=5 (over max): OK
OutputConfig without S3Bucket: ERROR -> Missing required parameter
in Settings.OutputConfig: "S3Bucket"
必須メンバーの欠落(S3BucketなしのOutputConfig)は検出されますが、存在しないenum値は素通りします。前節で触れた開発者ガイドの綴り違いをそのまま書き写しても、ローカルではエラーにならず、API呼び出しではじめて弾かれます。enumはリテラルを直書きせず、定数に寄せてテストで固定してください。
# challenges.py — enum は直書きせず1箇所に固定する
FACE_MOVEMENT_AND_LIGHT = "FaceMovementAndLightChallenge"
FACE_MOVEMENT = "FaceMovementChallenge"
AUDIT_IMAGES_LIMIT = 2 # 0-4。範囲外は例外にならず黙って丸められる
# tests/test_challenges.py
def test_challenge_values_match_api_model():
from botocore.session import get_session
model = get_session().get_service_model("rekognition")
shape = model.operation_model("CreateFaceLivenessSession").input_shape
enum = shape.members["Settings"].members["ChallengePreferences"].member.members["Type"].enum
assert FACE_MOVEMENT_AND_LIGHT in enum
assert FACE_MOVEMENT in enum
assert 0 <= AUDIT_IMAGES_LIMIT <= 4
AuditImagesLimitに5を渡した場合は事情が違います。こちらはローカルでもAPIでもエラーになりません。APIモデルの説明が「0未満は0、4を超えたら4枚を返す」と定めているとおり、黙って4へ丸められます。エラーで気づけない値なので、こちらもテストで固定しておく対象です。
スコアの扱いにも決まりがあります。開発者ガイドの推奨事項は「Face Livenessのスコアをユーザーアプリケーションへ送信・表示しない。合否のシグナルだけを送る」と明記しています。前掲のTSXが合否のbooleanだけを受け取っているのはこのためです。
実行環境の最低要件とCSPで塞がるモデル配信元
端末・カメラ・帯域の下限と、公式資料内で食い違う録画解像度
Face Livenessには利用者側の最低要件があります。前面カメラを備え、画面のリフレッシュレートが60Hz以上、画面サイズが4インチ以上、jailbreakやrootを施していないこと。カメラ側はカラー撮影が可能で、仮想カメラソフトではなく、15fps以上で記録できること。ネットワークは100kbps以上です。デスクトップでWebカメラを使う場合は、チェックを開始する画面の上部に取り付ける必要があります。対応ブラウザはChrome、Firefox、Safari、Edgeの最新3バージョンです。
録画解像度だけはAWSの資料内で数字が割れています。開発者ガイドは最低480×640ピクセル、AI Service Card(2023年11月27日時点の内容)は320×240としています。要件表を社内へ配る際は、高いほうの480×640で見積もっておくのが無難です。
モデル配信CDNの実際の既定値とCSPの許可
FaceLivenessDetectorは、顔検出をブラウザ内のTensorFlow.jsで行います。BlazeFaceのモデルとWebAssemblyバックエンドのバイナリを外部から取得するため、Content Security Policyを敷いている環境では取得元の許可が要ります。
ここに落とし穴があります。パッケージの型定義に付いているJSDocは、既定値をtfhub.devとcdn.jsdelivr.netだと説明しています。ところが3.6.8の実装コードを読むと、実際の定数はcdn.liveness.rekognition.amazonaws.comを指しています。JSDocの記述を信じてCSPを書くと、モデルの取得が拒否されて起動しません。
ズレはホスト名だけではありません。Amplify UIの公開ドキュメントはホスト名こそ正しいものの、既定のバージョンをWASMバイナリ3.11.0・BlazeFace 0.0.7と書いています。3.6.8の実装が参照しているのは4.11.0と1.0.2です。自社CDNへミラーする際は、ドキュメントの数字ではなくインストールしたパッケージの実装値を確認してください。
Content-Security-Policy:
script-src 'self' 'wasm-unsafe-eval';
connect-src 'self' https://cdn.liveness.rekognition.amazonaws.com
wss://streaming-rekognition.ap-northeast-1.amazonaws.com;
モデルもWASMバイナリもfetch()で取得されるためconnect-srcが要ります。加えてWebAssemblyのコンパイルは、CSPのscript-srcに'wasm-unsafe-eval'が無いとブラウザに拒否されます。映像のストリーミング先であるstreaming-rekognition.<region>.amazonaws.comへのWebSocket接続もconnect-srcの対象です。上の例は最小構成で、クロスオリジン分離を有効にした環境ではTensorFlow.jsがWorkerをblob URLから起動するためworker-src blob:も要ります。社内CDNから配りたい場合は、configのbinaryPathとfaceModelUrlで上書きできますが、WASMのバージョンはnpmが入れたもの(3.6.8では4.11.0)と揃える必要があります。
東京リージョンの単価とS3の同一リージョン制約
Face Livenessが使えるのは8リージョンです。単価はStartFaceLivenessSessionの呼び出し回数に対する段階制で、リージョンによって3割の差があります。以下はAWS Price List APIから取得した1回あたりのUSD単価です。
| リージョン | 50万回まで | 50万〜300万回 | 300万回超 |
|---|---|---|---|
| 米国東部(バージニア北部) | 0.0150 | 0.0125 | 0.0100 |
| 米国西部(オレゴン) | 0.0150 | 0.0125 | 0.0100 |
| 欧州(アイルランド) | 0.0150 | 0.0125 | 0.0100 |
| アジアパシフィック(ムンバイ) | 0.0180 | 0.0150 | 0.0120 |
| アジアパシフィック(東京) | 0.0195 | 0.0163 | 0.0130 |
| アジアパシフィック(マレーシア) | 0.0195 | 0.0163 | 0.0130 |
| アジアパシフィック(タイ) | 0.0195 | 0.0163 | 0.0130 |
| 南米(サンパウロ) | 0.0195 | 0.0163 | 0.0130 |
月100万回のチェックを想定すると、東京では17,900 USD、バージニア北部では13,750 USDになります。差は月4,150 USD、東京比で23%の削減です。しかも開発者ガイドのFAQは「AWSアカウントが別リージョンにあっても、レイテンシの差は大きくないと想定される」と書いています。速度を理由に東京を選ぶ根拠を、公式は見込んでいません。なお課金対象はStartFaceLivenessSessionの呼び出し回数なので、失敗した試行も1回として数えます。上の試算は成功1回=1呼び出しの前提で、再試行の分だけ上振れします。
それでも東京を選ぶ理由になるのはデータの所在です。リファレンス画像と監査画像をS3に保存する場合、そのバケットはFace Livenessのエンドポイントと同じリージョンになければなりません。異なる場合は画像をS3経由で受け取れず、生バイト列で受け取ることになります。顔画像を国内に置く要件があるなら東京、無いなら単価の安いリージョン、という切り分けになります。
SDKの更新義務|メジャー120日・マイナー180日の期限
Face Livenessには他のAWS機能にあまり無い制約があります。古いSDKからのリクエストが遮断され得る、という点です。開発者ガイドの「Face Liveness update guidelines」は次のように定めています。
メジャー版は、新しいメジャー版のリリース日から120日間だけ旧版をサポートし、120日を過ぎると旧メジャー版からのリクエストをブロックする場合があります。マイナー版は、新しいマイナー版のリリースから180日後にサポート終了が告知される場合があります。パッチ版は次のメジャー・マイナーが出るまで後方互換が保たれます。バージョン管理の対象は、StartFaceLivenessSession APIの一部であるユーザーチャレンジと、Amplify SDKで配布されるFaceLivenessDetectorコンポーネントの2つです。
@aws-amplify/ui-react-livenessのメジャー版は1.0.0が2023年4月11日、2.0.0が同年7月20日、3.0.0が同年11月16日で、現行は3.6.8(2026年7月28日)です。v1系やv2系を掴んだまま残っているプロジェクトは、120日の猶予をとうに過ぎています。運用としては、このパッケージを依存関係の自動更新から除外しないこと、そしてAmplifyのGitHubリリースを監視対象に入れておくことです。「動いているから触らない」が通用しない依存関係だと認識しておいてください。
Face Livenessを採用すべきでない条件
4つの条件のどれかに当てはまるなら、この機能は選ばないほうが早く着地します。
第1に、Amplifyを入れたくない場合です。SDKが必須である以上、フロントエンドの技術選定と衝突します。
第2に、利用者の端末が要件を満たさない場合です。4インチ未満の画面、60Hz未満のディスプレイ、100kbps未満の回線が想定に含まれるなら、真正ユーザーの誤拒否が構造的に発生します。窓口設置端末を自社で選定できるならまだしも、利用者の私物端末に依存する消費者向けサービスでは、この要件を満たさない層が必ず残ります。
第3に、「本人かどうか」を判定したい場合です。Face Livenessが答えるのは実在性だけなので、CompareFacesなどによる照合工程を別に組まないと本人確認としては成立しません。
第4に、ディープフェイクのようなデジタル注入攻撃が主たる脅威の場合です。AI Service Cardは高いしきい値(80〜90)ならこの種の攻撃の検出に適するとしつつ、決定はスコアと人間の判断の組み合わせによると釘を刺しています。開発者ガイドも、両方のチャレンジ種別について「映像を送出する端末そのものを保護する仕組みを実装者側で用意すべき」と書いています。カメラをバイパスされる攻撃モデルを想定するなら、Face Livenessは対策の一部でしかありません。この領域の手口はディープフェイク詐欺の手口と防御の解説で整理しています。
逆に、消費者向けの口座開設フローで、私物スマートフォンのブラウザから実在性を確認したい、というよくある要件には素直に嵌まります。開発者ガイドによれば、エンドツーエンドのレイテンシは最良で5秒、平均7秒、最悪11秒です。
よくある質問
Amplify SDKを使わずにFace Livenessを実装できますか?
できません。Rekognition開発者ガイドのFAQは「Amplify SDKなしでFace Liveness機能を使えるか」という質問に対して、Amplify SDKが必須だと明記しています。React、Swift(iOS)、Androidの3つのSDKにFaceLivenessDetectorコンポーネントが含まれており、ブラウザからのストリーミングはこのコンポーネントが担当します。自前でStartFaceLivenessSessionのイベントストリームを実装する構成は想定されていません。
Face Livenessは東京リージョンで使えますか?
使えます。提供リージョンはバージニア北部、オレゴン、アイルランド、東京、ムンバイ、サンパウロ、マレーシア、タイの8つです。ただし1回あたりの単価はリージョンで変わるので、本文の料金表で確認してください。東京で動かす場合に必要なのは、region propsへap-northeast-1を渡すことと、バックエンドのCreateFaceLivenessSessionも同じリージョンで呼ぶことの2点です。両者がずれると接続に失敗します。
顔認証APIとFace Livenessはどう違いますか?
役割が違います。CompareFacesやSearchFacesByImageといった顔照合APIは「2つの顔が同一人物か」を答えます。Face Livenessが答えるのは「カメラの前にいるのが実在の人物か」だけです。照合だけでは他人の顔写真をかざされたときに通過してしまうため、口座開設や本人確認のフローでは両方を組み合わせます。Face Livenessが返すリファレンス画像をそのまま照合APIに渡せる設計になっています。Rekognitionが持つAPI全体の守備範囲はAmazon Rekognitionの機能と料金の解説にまとめました。
スマートフォンのブラウザで画面の明るさは自動調整されますか?
Webでは自動調整されません。開発者ガイドのFAQによれば、iOSとAndroidのネイティブSDKはチェック開始時に画面輝度を自動で上げますが、WebのSDKにはWebページ側の制約があり自動調整ができません。そのため、Webで実装する場合はチェック開始前に「画面の明るさを最大にしてください」と利用者へ案内する必要があります。色光の反射を読むFaceMovementAndLightChallengeでは、輝度が足りないと真正ユーザーの通過率が下がる方向に効きます。
チェックに失敗し続けるユーザーはどう扱えばよいですか?
開発者ガイドが具体的な数字を挙げています。単一の端末からの失敗は3分間に5回まで。5回失敗したら30〜60分のタイムアウトを設け、同じパターンが3〜5回繰り返されるなら、その端末からの呼び出しをブロックします。あわせて推奨されているのが、監査画像に対する人手のレビューです。設定したしきい値でなりすましを止められているかを定期的に確認します。