JavaScript SDK (verifa.js)

The Verifa JavaScript SDK handles the frontend capture experience — opening the verification UI as a popup, modal, or redirect. Your backend creates the session, the SDK handles the rest.

The most secure and production-ready approach: your backend creates the session using a secret API key, then passes the capture_url to the frontend.

1. Add the script

1<script src="https://app.withverifa.com/static/verifa.js"></script>

2. Create a session on your server

Your backend calls the Verifa API with a secret key:

1import requests
2
3response = requests.post(
4 "https://api.withverifa.com/api/v1/sessions",
5 headers={"X-API-Key": "vk_live_your_secret_key"},
6 json={"external_ref": user_id, "country": "US"}
7)
8session = response.json()
9# Return session["id"] and session["capture_url"] to your frontend

3. Open the capture UI on your frontend

1<button id="verify-btn">Verify Identity</button>
2
3<script>
4 document.getElementById('verify-btn').addEventListener('click', async function () {
5 // Call YOUR backend to create a session
6 const res = await fetch('/api/create-verification', { method: 'POST' });
7 const session = await res.json();
8
9 // Open the Verifa capture UI
10 Verifa.open({
11 captureUrl: session.capture_url,
12 sessionId: session.id,
13 mode: 'popup', // or 'modal' or 'redirect'
14 onComplete: function (data) {
15 console.log('Verification submitted:', data.sessionId);
16 },
17 onClose: function () {
18 console.log('User closed without completing');
19 },
20 });
21 });
22</script>

This is how Stripe, Persona, and other platforms work — the API key never leaves your server. The frontend only receives a short-lived capture URL.

4. Get the result

Results contain PII and must be retrieved server-side:

$curl https://api.withverifa.com/api/v1/sessions/session_abc123/result \
> -H "X-API-Key: vk_live_your_secret_key"

Or receive results via webhook (recommended for production).


Quick start (publishable key)

For prototyping or simple integrations where you don’t have a backend, you can use a publishable key to create sessions directly from the browser.

Publishable keys are designed for quick prototyping and simple use cases. For production applications, use the recommended integration above — it keeps your API key on your server and gives you full control over session creation.

1<script src="https://app.withverifa.com/static/verifa.js"></script>
2
3<button id="verify-btn">Verify Identity</button>
4
5<script>
6 Verifa.init({ publishableKey: 'vk_pub_sandbox_your_key_here' });
7
8 document.getElementById('verify-btn').addEventListener('click', function () {
9 Verifa.startVerification({
10 externalRef: 'user_123',
11 country: 'US',
12 onComplete: function (data) {
13 console.log('Done:', data.sessionId, data.status);
14 },
15 });
16 });
17</script>

Publishable keys (vk_pub_*) can only create sessions — they cannot read results, access PII, or manage any resources. Create one in the dashboard under Developers > API Keys.


API reference

Open the capture UI for a session your backend already created. No API key needed in the browser.

ParameterTypeRequiredDescription
captureUrlstringYesThe capture_url from your session creation response.
sessionIdstringNoThe session ID (returned in callbacks). Recommended.
modestringNo"popup" (default), "modal", or "redirect".
redirectUrlstringNoURL to redirect to after completion (redirect mode only).
onCompletefunctionNoCalled with { sessionId, status } on success.
onErrorfunctionNoCalled with an Error on failure.
onClosefunctionNoCalled when the user closes without completing.

Returns: Promise<{ sessionId: string, status: string }>

1const result = await Verifa.open({
2 captureUrl: session.capture_url,
3 sessionId: session.id,
4 mode: 'modal',
5});

Verifa.init(options) — publishable key only

Initialize the SDK with a publishable key. Only needed if using startVerification().

ParameterTypeRequiredDescription
publishableKeystringYesYour publishable API key (starts with vk_pub_).
apiBasestringNoAPI base URL. Defaults to https://app.withverifa.com.

Verifa.startVerification(options) — publishable key only

Create a session using a publishable key and open the capture UI. Requires Verifa.init() first.

ParameterTypeRequiredDescription
externalRefstringNoYour internal user or reference ID.
countrystringNoISO 3166-1 alpha-2 country code.
modestringNo"popup" (default), "modal", or "redirect".
redirectUrlstringNoURL to redirect to after completion.
metadataobjectNoArbitrary key-value data attached to the session.
workflowIdstringNoRun a specific workflow.
onCompletefunctionNoCalled with { sessionId, status } on success.
onErrorfunctionNoCalled with an Error on failure.
onClosefunctionNoCalled when the user closes without completing.

Returns: Promise<{ sessionId: string, status: string }>


Display modes

Opens the capture UI in a centered popup window. Best for desktop.

1Verifa.open({
2 captureUrl: session.capture_url,
3 sessionId: session.id,
4 mode: 'popup',
5 onComplete: function (data) {
6 // Popup closes automatically
7 console.log('Done:', data.sessionId);
8 },
9 onClose: function () {
10 console.log('User closed the popup');
11 },
12});

If the browser blocks the popup, onError fires. Fall back to modal mode.

Opens the capture UI in a full-screen overlay with an iframe. Works on desktop and mobile. Closes with the X button, backdrop click, or Escape key.

1Verifa.open({
2 captureUrl: session.capture_url,
3 sessionId: session.id,
4 mode: 'modal',
5 onComplete: function (data) {
6 console.log('Done:', data.sessionId);
7 },
8});

Redirect

Navigates the browser to the capture page. After completion, the user returns to the redirect_url you specified when creating the session.

1Verifa.open({
2 captureUrl: session.capture_url,
3 mode: 'redirect',
4});

The user lands back on your redirect URL with query parameters:

https://your-app.com/verify/complete?session_id=session_abc123&status=completed

Framework examples

React

1import { useCallback } from 'react';
2
3function VerifyButton({ userId }) {
4 const handleClick = useCallback(async () => {
5 // Your backend creates the session
6 const res = await fetch('/api/create-verification', {
7 method: 'POST',
8 headers: { 'Content-Type': 'application/json' },
9 body: JSON.stringify({ userId }),
10 });
11 const session = await res.json();
12
13 // Open the capture UI
14 const result = await window.Verifa.open({
15 captureUrl: session.capture_url,
16 sessionId: session.id,
17 mode: 'modal',
18 });
19
20 if (result.status === 'completed') {
21 // Notify your backend
22 await fetch('/api/verification-submitted', {
23 method: 'POST',
24 headers: { 'Content-Type': 'application/json' },
25 body: JSON.stringify({ sessionId: result.sessionId }),
26 });
27 }
28 }, [userId]);
29
30 return <button onClick={handleClick}>Verify Identity</button>;
31}

Vue

1<template>
2 <button @click="startVerification">Verify Identity</button>
3</template>
4
5<script setup>
6const startVerification = async () => {
7 const res = await fetch('/api/create-verification', { method: 'POST' });
8 const session = await res.json();
9
10 const result = await window.Verifa.open({
11 captureUrl: session.capture_url,
12 sessionId: session.id,
13 mode: 'modal',
14 });
15 console.log('Done:', result.sessionId);
16};
17</script>

Vanilla JavaScript

1document.getElementById('verify-btn').addEventListener('click', async () => {
2 const res = await fetch('/api/create-verification', { method: 'POST' });
3 const session = await res.json();
4
5 try {
6 const { sessionId, status } = await Verifa.open({
7 captureUrl: session.capture_url,
8 sessionId: session.id,
9 });
10
11 if (status === 'completed') {
12 showSuccess('Verification submitted!');
13 }
14 } catch (err) {
15 showError(err.message);
16 }
17});

Error handling

1Verifa.open({
2 captureUrl: session.capture_url,
3 sessionId: session.id,
4 mode: 'popup',
5 onError: function (err) {
6 if (err.message.indexOf('Popup blocked') >= 0) {
7 // Fall back to modal mode
8 Verifa.open({
9 captureUrl: session.capture_url,
10 sessionId: session.id,
11 mode: 'modal',
12 onComplete: handleComplete,
13 });
14 } else {
15 showError(err.message);
16 }
17 },
18 onComplete: handleComplete,
19});

Common errors:

ErrorCauseFix
captureUrl is requiredMissing capture URLPass capture_url from session creation
Popup blockedBrowser blocked the popupUse mode: 'modal' instead
publishableKey is requiredinit() not called before startVerification()Call init() first, or use open()
Failed to create verification sessionInvalid publishable key or rate limitedCheck key; retry after delay

Sandbox testing

Use sandbox API keys to test without real verifications. In sandbox mode, the capture flow lets you choose the outcome (approve, reject, or needs review).

1// Backend creates session with sandbox key (vk_sandbox_*)
2// Frontend uses the capture_url — same code, no changes needed
3Verifa.open({
4 captureUrl: sandboxSession.capture_url,
5 sessionId: sandboxSession.id,
6 onComplete: function (data) {
7 console.log('Sandbox result:', data.status);
8 },
9});

Browser support

The SDK uses fetch, Promise, and postMessage, supported in all modern browsers:

  • Chrome 42+, Firefox 39+, Safari 10.1+, Edge 14+

No polyfills required for any browser released after 2017.

Security

  • No API key in the browser — With Verifa.open(), the secret key stays on your server. The frontend only receives a short-lived capture URL (20 min).
  • No PII exposure — The SDK never receives verification results, document images, or personal data.
  • Token-based capture — Document uploads use a session-specific token, not any API key.