Web quickstart
From nothing to a verified verdict. Every snippet below runs as written.
- 1
Install the client
The npm publish is still pending, so today the working install is from a clone:
bashgit clone https://github.com/neetixai/liveliness-sdks npm i ./liveliness-sdks/packages/webdist/is not committed — the package'spreparescript compiles it during install. Once the registry publish lands this becomesnpm i @neetix/livelinesswith no other change.Zero runtime dependencies — it uses the platform
fetch. Node 18+ or any current browser. - 2
Get a test key
bashcurl -X POST https://liveliness.neetix.in/v1/signup \ -H 'Content-Type: application/json' \ -d '{"email":"you@company.com"}'Keep the
test_api_key(lv_test_…). It is unmetered, so nothing below costs you credits while you build. - 3
Create the client
tsimport { NeetixClient } from "@neetix/liveliness"; const client = new NeetixClient({ apiKey: process.env.NEETIX_API_KEY });baseUrldefaults tohttps://liveliness.neetix.in. Pass it only when you self-host.Server-side only for a live keyA live key in browser JavaScript is readable by anyone on the page. From the browser, either use a test key for a demo, or proxy through your own backend and keep the live key there. For user-facing capture in production, use hosted verification links or the on-device edge build instead of shipping a key.
- 4
Make the call
Face match takes the selfie and the ID photo, and costs 2 credits:
tsconst res = await client.faceMatch(selfieBlob, idPhotoBlob, { clientRefId: "application-4821", }); console.log(res.verdict); // "approved" | "review" | "declined" console.log(res.warnings); // ["LOW_LIGHT", ...] console.log(res.result.is_same_face); console.log(res.result.liveness_score); console.log(res.mode); // "test" — proves which key ranIn a browser,
selfieBlobis whatever your<input type="file">or canvas gives you. In Node, read the file into aBlob:tsimport { readFile } from "node:fs/promises"; const selfie = new Blob([await readFile("selfie.jpg")], { type: "image/jpeg" }); const idPhoto = new Blob([await readFile("id.jpg")], { type: "image/jpeg" }); - 5
Branch on the verdict
tsswitch (res.verdict) { case "approved": return continueJourney(); case "review": return queueForManualReview(res.warnings); case "declined": return stop(res.warnings); }Do not re-derive a decision from
liveness_score— the verdict already applied the thresholds, and a hand-rolled cutoff is the most common way these integrations go wrong.
Handle errors as errors
Failures throw NeetixApiError, which carries the HTTP status and the
server's message_code:
import { NeetixApiError } from "@neetix/liveliness";
try {
const res = await client.faceMatch(selfie, idPhoto);
} catch (err) {
if (err instanceof NeetixApiError) {
if (err.isInsufficientCredits) {
// HTTP 402 — the prepaid balance is gone. Every call fails until top-up.
return haltAndAlert();
}
console.error(err.status, err.messageCode, err.message);
}
throw err;
}The codes you will actually meet: no_face_detected (422),
insufficient_credits (402), unauthorized (401).
Liveliness on its own
When you already hold a selfie and only need the liveliness check — 1 credit:
const live = await client.liveness(selfieBlob);
console.log(live.status); // "Approved" | "Declined" | "Not Finished"
console.log(live.liveness_score);Next
- Get started — verdicts, warnings and credits in depth.
- API reference — the full REST surface, generated from the OpenAPI document the server serves.