Skip to main content

Web SDK

The Kora IDV Web SDK ships as two npm packages:

  • @koraidv/core — framework-agnostic. API client, verification engine, capture pipeline, types. Use this directly from vanilla JS, Vue, Svelte, Solid, etc.
  • @koraidv/react — React components and hooks built on top of @koraidv/core. Drop-in screens (<VerificationFlow />, <DocumentCaptureScreen />, <LivenessScreen />) plus a useKoraIDV hook.

Both run entirely in the browser — camera capture via getUserMedia, document detection and liveness inference via in-browser ML models. No additional server install required.

Requirements

  • Modern browser with getUserMedia and WebAssembly support (Chrome 90+, Safari 16+, Firefox 90+, Edge 90+)
  • Site served over HTTPS (camera APIs are gated to secure contexts)
  • Bundler that supports ES modules (Vite, Webpack 5, esbuild, Rollup, etc.)

Installation

React

npm install @koraidv/react @koraidv/core react react-dom

@koraidv/core is a peer of @koraidv/react, so install both. react and react-dom are also peers (>= 17).

Vanilla / non-React

npm install @koraidv/core

Quick start (React)

import { KoraIDVProvider, VerificationFlow } from '@koraidv/react';

function App() {
return (
<KoraIDVProvider
apiKey="kora_sandbox_xxxxx"
tenantId="your-tenant-uuid"
config={{ environment: 'sandbox' }}
>
<VerificationFlow
externalId={`user-${userId}`}
tier="standard"
onComplete={(v) => console.log('done', v.riskScore)}
onError={(e) => console.error(e.code)}
onCancel={() => console.log('cancelled')}
/>
</KoraIDVProvider>
);
}

The provider takes apiKey and tenantId directly; everything else (environment, theme, livenessMode) goes inside the config prop.

<VerificationFlow> renders the full multi-step UI: country selection → document type → document capture → selfie → liveness → result. The onComplete callback fires once the verification reaches a terminal state.

Quick start (vanilla JS)

@koraidv/core exposes a granular pipeline API rather than a single mounted-component flow. You drive the steps yourself or render UI with @koraidv/react's individual screen components. The minimal callback-driven flow:

import { KoraIDV } from '@koraidv/core';

const kora = new KoraIDV({
apiKey: 'kora_sandbox_xxxxx',
tenantId: 'your-tenant-uuid',
environment: 'sandbox',
});

await kora.startVerification(
{
externalId: `user-${userId}`,
tier: 'standard',
},
{
onComplete: (verification) => {
console.log('Risk score:', verification.riskScore);
},
onStepChange: (step) => {
console.log('Now on step:', step);
},
onError: (err) => console.error(err.code, err.message),
onCancel: () => console.log('cancelled'),
}
);

After startVerification resolves, call kora.uploadDocument(blob, 'front', docType), kora.uploadSelfie(blob), kora.startLivenessSession() / kora.submitLivenessChallenge(...), and finally kora.completeVerification(). Most consumers reach for @koraidv/react's flow components instead — they wrap these calls behind a state machine.

Composing your own UI

If you want full control over layout and styling, import the individual screen components and build your own state machine. They all live under @koraidv/react:

import {
CountrySelectionScreen,
DocumentSelectionScreen,
DocumentCaptureScreen,
SelfieCaptureScreen,
LivenessScreen,
ResultScreen,
StepProgressBar,
} from '@koraidv/react';

Each accepts its own props (selected country, document type, image data, callbacks). See the package source for full prop types.

Configuration

type Configuration = {
apiKey: string;
tenantId: string;
environment?: 'sandbox' | 'production'; // auto-detected from key prefix
baseUrl?: string; // override for on-prem
livenessMode?: 'active' | 'passive';
theme?: {
primaryColor?: string;
backgroundColor?: string;
textColor?: string;
cornerRadius?: number;
};
timeout?: number; // ms, default 120000
};

For React, apiKey and tenantId go on the provider directly; everything else nests under config:

<KoraIDVProvider
apiKey=""
tenantId=""
config={{
environment: 'production',
livenessMode: 'active',
theme: { primaryColor: '#0D9488' },
}}
>
<App />
</KoraIDVProvider>

Hook (React)

useKoraIDV() returns a state object plus action methods:

import { useKoraIDV } from '@koraidv/react';

function VerifyPage() {
const { state, startVerification, resumeVerification, acceptConsent } = useKoraIDV();

// state.step, state.verification, state.error, state.isLoading

return (
<div>
{state.step === 'idle' && (
<button onClick={() => startVerification(`user-${id}`, 'standard')}>
Start
</button>
)}
{state.verification && (
<div>Risk score: {state.verification.riskScore}</div>
)}
</div>
);
}

Verification tiers

TierIncludes
basicDocument OCR + basic authenticity
standard+ Face match + active liveness
enhanced+ Anti-spoof + risk signals + compliance screening (sanctions / PEP / adverse media)

Camera permissions

The SDK calls navigator.mediaDevices.getUserMedia({ video: true }) when capture starts. Browsers will show a permission prompt the first time. If the user denies, the SDK fires onError with KoraErrorCode.CAMERA_ACCESS_DENIED; you can prompt the user to update their browser settings.

QR handoff (desktop → mobile)

If your verification is initiated on desktop but you'd rather the user finish on their phone, use the QR handoff component:

import { QrHandoffScreen } from '@koraidv/react';

<QrHandoffScreen
verificationId={existingVerificationId}
onScanned={() => {/* user scanned, started on mobile */}}
/>

The mobile device can resume by opening the URL encoded in the QR code, which carries the verification ID and a short-lived token.

Security

  • The SDK only accepts API keys with the kora_sandbox_… or kora_live_… prefix. The key is sent on every request as Authorization: Bearer <key>.
  • Treat your API key as a secret. Don't ship it in client-side code for production verifications. Instead, mint a short-lived session token from your backend and configure the SDK with that:
    // Backend (Go SDK)
    token, err := client.CreateSessionToken(ctx, externalId, "standard")
    // Returns kora_session_… valid for 30 minutes, scoped to one verification
    // Frontend
    new KoraIDV({ apiKey: token, tenantId, environment: 'production' })
  • All communication is HTTPS. The SDK rejects requests over plain HTTP.

Bundle size

PackageMin + gzip
@koraidv/core~38 kB
@koraidv/react~39 kB on top of core

Heavy dependencies (TensorFlow, OpenCV WASM) are loaded lazily on first capture. Initial JS bundle stays small enough for most performance budgets.

Common issues

IssueFix
getUserMedia is not a functionSite must be served over HTTPS (or localhost).
Camera prompt not appearingEnsure no other tab/page is holding the camera; clear the permission and reload.
Module not found: @koraidv/core from ReactInstall both packages — @koraidv/core is a peer dep of @koraidv/react.
TypeScript can't find typesBoth packages ship .d.ts files in dist/. Confirm your tsconfig.json moduleResolution is bundler or node16+.

Next steps