React SDK
@facegate/react is the drop-in face authentication component. It owns the camera, the liveness challenge, and the QR fallback for devices without a camera. You give it an API key and an onAuthenticated callback. Everything else ships inside the component.
It targets React 18 and 19. The core is the <FaceGate /> component plus a small set of theme and consent helpers.
Install
npm install @facegate/reactIf you are minting a Supabase session from the scan, also install the adapter:
npm install @facegate/react @facegate/supabaseUsage
import { FaceGate } from '@facegate/react';
export function SignIn() {
return (
<FaceGate
apiKey="fg_test_your_key_here"
mode="verify"
onAuthenticated={(session) => {
// session.token — signed JWT
// session.user — { id, name, role, metadata }
// session.provider_session — provider tokens (Tier 2), or null
console.log('Signed in as', session.user.name);
}}
onError={(err) => console.error(err)}
/>
);
}That is the entire client integration. No camera permission UI to build, no liveness logic to write.
Props
These are the props on the FaceGateProps type (sdk/react/src/FaceGate.tsx, lines 17–28). Document only what is in the type — there are no other props.
| Prop | Type | Default | Description |
|---|---|---|---|
apiKey | string | — | Your FaceGate API key (fg_test_… in development). Required unless supplied by <FaceGateProvider />. If missing, the component renders an error. |
serverUrl | string | https://api.facegate.ai | FaceGate API base URL. Override for self-hosted servers. |
mode | 'verify' | 'enroll' | 'verify' | verify authenticates an existing user. enroll captures a new face. See Modes. |
liveness | boolean | true | Require a liveness challenge (head movements) after the face match. Leave on for anti-spoofing. |
onAuthenticated | (session: FaceGateSession) => void | — | Fired on a successful verification. Receives the session. |
onError | (error: Error) => void | — | Fired on camera, network, or verification failure. |
enrollment | { name: boolean; email?: boolean; phone?: boolean } | { name: true } | Which fields to collect during enroll mode. Ignored in verify mode. |
theme | 'dark' | 'light' | Record<string, string> | 'dark' | Preset name or a map of theme overrides. See Theming. |
fallback | 'qr' | 'none' | 'qr' | Behavior when the device has no usable camera. qr shows a scan-to-continue code; none shows an error. See QR fallback. |
Modes
mode selects what the component does with the captured face.
| Mode | What it does | What you get back |
|---|---|---|
verify | Matches the face against an enrolled user and runs liveness. | A FaceGateSession via onAuthenticated. |
enroll | Captures a new face and collects the fields named in enrollment. | A FaceGateSession for the newly enrolled user via onAuthenticated. |
<FaceGate
apiKey="fg_test_your_key_here"
mode="enroll"
enrollment={{ name: true, email: true }}
onAuthenticated={(session) => {
console.log('Enrolled', session.user.id);
}}
/>The session shape
onAuthenticated receives a FaceGateSession. The type is re-exported from @facegate/react and defined in @facegate/client (sdk/client/src/types.ts, lines 61–74).
import type { FaceGateSession } from '@facegate/react';
interface FaceGateSession {
token: string; // signed JWT access token
refresh_token: string; // refresh token
expires_in: number; // token expiry in seconds
user: {
id: string;
name: string;
role: string | null;
metadata: Record<string, unknown>;
};
provider_session: Record<string, unknown> | null; // provider tokens (Tier 2), or null
confidence?: number; // face-match confidence (0–100)
}For Tier 1 (Verify), use token directly — you manage sessions yourself. For Tier 2 (Adapt), hand the whole session to your provider adapter; provider_session carries the tokens it needs.
Provider
To avoid passing apiKey to every <FaceGate />, wrap your app in <FaceGateProvider />. Props passed directly to <FaceGate /> still win.
| Prop | Type | Default | Description |
|---|---|---|---|
apiKey | string | — | API key inherited by descendant <FaceGate /> components. |
serverUrl | string | https://api.facegate.ai | Server URL inherited by descendants. |
children | ReactNode | — | Your app tree. |
import { FaceGateProvider, FaceGate } from '@facegate/react';
export function App() {
return (
<FaceGateProvider apiKey="fg_test_your_key_here">
<FaceGate mode="verify" onAuthenticated={handleAuth} />
</FaceGateProvider>
);
}Theming
Pass theme="dark" (the default) or theme="light" for a preset, or a Record<string, string> to override individual tokens.
For programmatic control, @facegate/react exports LIGHT_THEME, DARK_THEME, and resolveTheme, plus the FaceGateTheme type. resolveTheme merges your overrides onto a preset and resolves colorScheme: 'auto' against the system preference.
import { resolveTheme } from '@facegate/react';
const brand = resolveTheme({
colorScheme: 'auto', // 'dark' | 'light' | 'auto'
accentColor: '#6366f1',
borderRadius: '20px',
});
<FaceGate apiKey="fg_test_your_key_here" theme={brand} />;The FaceGateTheme tokens (sdk/react/src/theme.ts, lines 1–12):
| Token | Type | Description |
|---|---|---|
colorScheme | 'dark' | 'light' | 'auto' | Base scheme. auto follows the system preference. |
accentColor | string | Primary accent (oval, progress, success). |
backgroundColor | string | Component background. |
textColor | string | Primary text. |
mutedColor | string | Secondary text and hints. |
borderColor | string | Borders and dividers. |
errorColor | string | Error state. |
successColor | string | Success state. |
borderRadius | string | Corner radius. |
fontFamily | string | Font stack. |
QR and camera fallback
When the device has no usable camera, fallback decides what happens:
fallback="qr"(default) renders a QR code. The user scans it with a phone, authenticates there, and the original session activates over a WebSocket. No code on your side.fallback="none"renders an error instead.
The component detects the camera and switches automatically — you do not branch on device type.
Consent
@facegate/react also exports the BiometricConsent component plus the CONSENT_TEXT string and getConsentHash helper, for jurisdictions that require explicit biometric consent before enrollment. Gate mode="enroll" behind <BiometricConsent /> where you need a recorded opt-in.
Next steps
- Next.js — App Router setup,
'use client', and SSR notes. - Supabase adapter — turn a scan into a real Supabase session.
- REST API — call the endpoints directly without the SDK.