Every yes:id SDK module needs a valid session before it can run. Complete the Sessions Guide first, it takes 5 minutes and is required before the code below will work.
Using the Liveness SDK
The user starts the check, completes on-screen challenges (blink, look left / right / up / down, look at the camera), and the SDK submits the result to the session.
Create the session on your backend. The browser only receives publishableKey and sessionId.
Prerequisites β create a session firstβ
const [config, session] = await Promise.all([fetch("/config").then(r => r.json()), fetch("/create-session", { method: "POST" }).then(r => r.json())]);
const publishableKey = config.publishableKey; // pk_β¦
const sessionId = session.sessionId; // vs_β¦
Enable liveness (and faceMatch if you need matching) when you create the session. See the Sessions Guide.
Web componentβ
<script type="module">
import { defineYesIdLiveness } from "@yesid/liveness-sdk/component";
defineYesIdLiveness();
</script>
<liveness-check id="liveness" publishable-key="pk_live_xxx" overlay-mode="light" start-label="Start"></liveness-check>
<script>
const el = document.getElementById("liveness");
el.sessionId = sessionId;
el.addEventListener("yesid:success", event => {
console.log(event.detail.response);
console.log(event.detail.submission);
});
el.addEventListener("yesid:failure", event => {
console.error(event.detail.reason, event.detail.message);
});
</script>
You can also assign properties and start the flow yourself:
el.publishableKey = publishableKey;
el.sessionId = sessionId;
await el.start();
el.stop();
If auto-start is not set, the component renders its own start UI.
Reactβ
import { LivenessReact } from "@yesid/liveness-sdk/react";
export function LivenessStep({ publishableKey, sessionId }) {
return (
<LivenessReact
publishableKey={publishableKey}
sessionId={sessionId}
overlayMode="light"
startLabel="Start"
onSuccess={({ response, submission }) => {
console.log(response.status);
console.log(submission.captures.length);
}}
onFailure={event => {
console.error(event.detail.reason, event.detail.message);
}}
/>
);
}
Configuration referenceβ
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
publishableKey / publishable-key | string | Yes | β | Browser-safe key (pk_β¦) |
sessionId / session-id | string | Yes | β | Session created by your backend (vs_β¦) |
autoStart / auto-start | boolean | No | false | Start immediately after mount |
startLabel / start-label | string | No | Start | Start button text |
overlayMode / overlay-mode | 'dark' | 'light' | No | dark | Overlay theme |
challengeLabels | ChallengeLabels | No | SDK defaults | Override challenge copy |
overlayLabels | OverlayLabels | No | SDK defaults | Override overlay copy |
className / style | β | No | β | Passed through to the underlying element |
Callbacks (React)β
| Prop | Fired when | Argument |
|---|---|---|
onSuccess | Liveness passes and results are submitted | { response, submission } |
onFailure | Liveness, session, or submission fails | CustomEvent<LivenessError> |
onCapture | A challenge capture is produced | CustomEvent<LivenessCapture> |
onSessionValidated | Session validation returns valid | CustomEvent<SessionValidatedEvent> |
onSessionInvalid | Session is invalid or expired | CustomEvent<SessionInvalidEvent> |
Customising labelsβ
import { LivenessReact } from "@yesid/liveness-sdk/react";
const challengeLabels = {
BLINK: { text: "Blink once", hint: "Close and open both eyes once." },
LOOK_CENTER: { text: "Hold still", hint: "Look straight at the camera." },
};
const overlayLabels = {
start: {
title: "Ready to verify",
hint: "Keep your face inside the oval and follow the instructions.",
button: "Start",
},
permissionDenied: {
title: "Camera blocked",
text: "Allow camera access in your browser settings to continue.",
button: "Retry",
},
};
<LivenessReact publishableKey={publishableKey} sessionId={sessionId} challengeLabels={challengeLabels} overlayLabels={overlayLabels} />;
On the web component, assign the same objects to el.challengeLabels and el.overlayLabels. Defaults are available from @yesid/liveness-sdk as getDefaultChallengeLabels() and getDefaultOverlayLabels().
Themingβ
The React wrapper and web component share CSS custom properties:
.brand-liveness {
--yesid-max-width: 440px;
--yesid-aspect-ratio: 4 / 3;
--yesid-video-bg: #f4f7fb;
--yesid-text-color: #0f172a;
--yesid-oval-color: rgba(14, 116, 144, 0.55);
--yesid-oval-detected: rgba(22, 163, 74, 0.9);
--yesid-start-button-bg: linear-gradient(135deg, #0ea5e9, #67e8f9);
--yesid-start-button-color: #082f49;
}
<LivenessReact className="brand-liveness" publishableKey={publishableKey} sessionId={sessionId} />
Complete React exampleβ
This mirrors the yes:id web demo β create a session, run liveness, then handle an expired session by creating a new one:
import { useCallback, useEffect, useState } from "react";
import { LivenessReact } from "@yesid/liveness-sdk/react";
export function LivenessScreen() {
const [publishableKey, setPublishableKey] = useState("");
const [sessionId, setSessionId] = useState("");
const [done, setDone] = useState(false);
const [error, setError] = useState("");
const createSession = useCallback(async () => {
setDone(false);
setError("");
try {
const [config, session] = await Promise.all([
fetch("/config").then(r => r.json()),
fetch("/create-session", { method: "POST" }).then(r => r.json()),
]);
setPublishableKey(config.publishableKey);
setSessionId(session.sessionId);
} catch (e) {
setError(e instanceof Error ? e.message : "Failed to create session");
}
}, []);
useEffect(() => {
createSession();
}, [createSession]);
if (!publishableKey || !sessionId) {
return <p>{error || "Creating liveness sessionβ¦"}</p>;
}
if (done) {
return <p>Liveness complete.</p>;
}
return (
<LivenessReact
publishableKey={publishableKey}
sessionId={sessionId}
overlayMode="light"
startLabel="Start"
onSuccess={() => setDone(true)}
onFailure={event => {
const reason = event.detail?.reason;
if (reason === "CHALLENGE_TIMEOUT" || reason === "CAMERA_PERMISSION_DENIED") {
return;
}
setError(event.detail?.message || "Liveness check failed");
}}
onSessionInvalid={createSession}
/>
);
}
Read the success payload and poll session results for face match: Handling Results β