SDK
Embed the verify widget on a page. Five integration paths, identical verification behavior — pick what fits your stack. All paths are server-integrated as of v0.5.0 (2026-05-19) — every path produces a server-signed token.
Install
npm: npm install @verifyhuman/sdk (current version 0.5.0).
CDN: <script src="https://verifyhuman.riwi.com/sdk/v1/verifyhuman.umd.js" async defer></script>
Integration paths
1. HTML drop-in (auto-init)
Zero JS. The script auto-discovers elements with data-sitekey on page load and mounts a server-integrated widget. Use data-study-id / data-respondent-id / data-metadata for cross-reference; the values echo back on token / webhook responses.
<script src="https://verifyhuman.riwi.com/sdk/v1/verifyhuman.umd.js" async defer></script>
<div
data-sitekey="YOUR_SITE_KEY"
data-study-id="YOUR_STUDY_ID"
data-respondent-id="YOUR_RESPONDENT_ID"
data-metadata='{"panel":"prolific"}'
data-theme="light"
data-callback="onVerify"
></div>
<script>
function onVerify(result) {
// result.sessionId, result.token, result.scores, ...
fetch('/your-app/verified', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sessionId: result.sessionId,
token: result.token,
}),
});
}
</script>2. HTML + JS API
Programmatic mount when the auto-init element isn't present in your DOM at load time. Use window.VerifyHuman.VH.mount(...) from the CDN bundle.
<div id="vh-container"></div>
<script>
window.VerifyHuman.VH.mount(
document.getElementById('vh-container'),
{
siteKey: 'YOUR_SITE_KEY',
studyId: 'YOUR_STUDY_ID',
respondentId: 'YOUR_RESPONDENT_ID',
metadata: { panel: 'prolific' },
}
).then((result) => {
console.log('verified', result.sessionId, result.token);
});
</script>3. React
import { VerifyHuman } from '@verifyhuman/sdk/react';
function MyForm() {
const handleVerify = (token, result) => {
fetch('/api/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token }),
});
};
return (
<VerifyHuman
siteKey="YOUR_SITE_KEY"
studyId="YOUR_STUDY_ID"
respondentId="YOUR_RESPONDENT_ID"
metadata={{ panel: 'prolific' }}
widgetMode="standard" // 'invisible' | 'captcha' | 'standard'
onVerify={handleVerify}
onError={(err) => console.error(err)}
/>
);
}4. Next.js
Same React component with the 'use client' directive at the top of the file. Works with the App Router and the Pages Router.
5. Vanilla TypeScript
import { VH } from '@verifyhuman/sdk';
const result = await VH.mount('#verify-container', {
siteKey: 'YOUR_SITE_KEY',
studyId: 'YOUR_STUDY_ID',
respondentId: 'YOUR_RESPONDENT_ID',
});
// result.sessionId, result.token, result.scores, ...Widget modes
Set on the project server-side (dashboard → project → Settings) — not in the SDK. The SDK reads the configured mode from /projects/{siteKey}/public-config at mount time.
- Invisible — no UI, behavioral + device signals only. Escalates to camera challenge if signals are weak.
- CAPTCHA — one-click verify, escalates to camera only when needed.
- Standard — full camera-driven flow with liveness checks. Strongest signal.
Dispatch modes
- BLOCK — the widget gates pass / fail locally; your
onVerifycallback gets the JWT and you forward it to your backend for/token/verify. Default behavior. - SCORE — callback — non-blocking; the SDK fetches a signed score envelope from
/public/sessions/{id}/resultand fires youronResult. The envelope carriesscores,studyId,respondentId,metadata,failureReasons. - SCORE — redirect — server-signed redirect URL handoff. Validate the embedded
vh_tokenclient-side via JWKS for offline verification. - SCORE — visual handoff — replaces the widget with a
cdn.verifyhuman.io/handoffiframe. Used when you want VerifyHuman's UI to show the verdict, not your own.
Server-side token verification
Whichever embed path you pick, validate the JWT server-side before granting access to your protected content. Pattern:
POST https://verifyhuman.riwi.com/api/v1/token/verify
X-API-Key: YOUR_SECRET_KEY
Content-Type: application/json
{ "token": "TOKEN_FROM_CLIENT" }
# →
{
"success": true,
"sessionId": "sess_abc123",
"status": "pass",
"scores": { "liveness": 0.95, "uniqueness": 0.98, ... },
"studyId": "study_001",
"respondentId": "resp_456"
}Batch up to 100 tokens via POST /token/verify-batch — see the API reference.
For project-specific snippets
Sign in to the dashboard, open your project, click Integrate. The page renders snippets pre-filled with your site key, allowed origins, and your project's configured widget mode.
Configuration nuances
For project-level thresholds, retry / mode escalation, the SCORE envelope shape, and custom branding, see the configuration guide in the public repo.