Connection

KYC Widget

A browser-based identity verification flow: document capture, selfie, and liveness check (anti-spoofing). There are four ways to integrate it:

  1. <script> tag in a plain JavaScript app — window.KYCWidget.setupKYC({...})
  2. npm package kyc-widget-nv in a React app — <KycWidget ... />
  3. <script> tag in a React app
  4. Direct link (no integration) — https://kyc.neuro-vision.ru

Configuration parameters

ParameterTypeRequiredDefaultDescription
scenarioIdstringYes*Unique scenario identifier from the “KYC/AML” section of your dashboard (*not required when using taskId)
clientKeystringYes*Unique string (max 36 characters) that is passed encrypted; sample encryption code is available in the dashboard under “KYC/AML” (*not required when using taskId)
clientUserstringNoClient-side user identifier, max 36 characters. It doesn’t have to be unique: pass the same value across different sessions so you can later search by it and find all sessions (attempts) for that user
taskIdstringNoIdentifier of a verification task created in advance via the API. If set, the widget opens that task directly, and scenarioId/clientKey are not needed
isOpenbooleanYes*Widget visibility (*required only for the React component)
themelightdarkNoscenario setting
stickySessionbooleanNofalse“Sticky” sessions: the widget remembers the clientKey for the scenario (in localStorage, for 15 minutes). Reopening it in this window continues the previous session, even if a different clientKey is passed
closeCbfunctionNoCallback fired when the widget is closed
successCbfunctionNoCallback fired on successful verification. Receives the session result as a JSON string
finalizedCbfunctionNoCallback fired when the widget is opened for a session that was already finalized earlier. Receives { status }
topOffsetnumberNo0Top offset in pixels
bottomOffsetnumberNo0Bottom offset in pixels
blurHostbooleanNofalseIf true, the widget background is rendered as “frosted glass” over the host page (no background image and no right-hand blur panel) — the host page shows through a semi-transparent blurred layer
mountElementIdstringNoOnly for the script-tag integration (widget-lib.js). If set, the widget is mounted inline inside the element with this id instead of over the whole page. The widget fills the host element (width/height: 100%), so give the element explicit dimensions. See the example below. Not supported inside a cross-origin iframe — the browser will block the camera; in that case closeCb is called so the host can reset its state. Do not call setupKYC inside closeCb — repeated iframe detections will loop

successCb callback payload

successCb receives the verification result as a JSON string. The exact set of fields depends on the scenario steps (a document step arrives as "type": "document", liveness as "type": "liveness", and so on). Abbreviated example:

{
  "sessionId": "098d57-...",
  "status": "success",
  "errors": [],
  "results": [
    {
      "type": "liveness",
      "status": "success",
      "errors": [],
      "tries": 1,
      "startedAt": "2026-07-19T09:41:37.590Z",
      "faces": ["https://..."],
      "video": "https://..."
    }
  ],
  "schemaId": "3676-...",
  "clientKey": "46d1c-...",
  "clientUser": "",
  "createdAt": "2026-07-19T09:41:37.000Z",
  "secondsToLive": 0
}

1. Example: integrating into a JavaScript app via a script tag (index.html)

  1. Create a button in an initial loading state.
  2. Load the script dynamically and enable the button once it’s ready.
  3. Call window.KYCWidget.setupKYC() on button click.

File: index.html

  <body>
    <button id="btn" disabled>Loading...</button>

    <script>
      const btn = document.getElementById("btn");

      const script = document.createElement("script");
      script.src = "https://kyc.neuro-vision.ru/lib/widget-lib.js";
      script.onload = () => {
        btn.disabled = false;
        btn.textContent = "Open KYC widget";
      };
      script.onerror = () => {
        btn.textContent = "Failed to load KYC widget";
      };
      document.body.appendChild(script);

      const openWidget = () => {
        window.KYCWidget.setupKYC({
          scenarioId: "scenarioId",
          clientKey: "clientKey",
          clientUser: "clientUser",
          theme: "light",
          stickySession: true,
          topOffset: 0,
          bottomOffset: 0,
          // Optional. If set, the widget is mounted INSIDE the element
          // with this id (inline block) instead of over the whole page. The
          // element must exist in the DOM. On close, the element is cleared.
          // ⚠️ Do not open the host page inside a cross-origin <iframe> —
          // the browser will block getUserMedia and the camera won't start.
          // mountElementId: "kyc-here",
          closeCb: () => console.log("CLOSE CALLBACK"),
          successCb: (sessionJson) => console.log("SUCCESS CALLBACK", sessionJson),
          finalizedCb: ({ status }) => console.log("FINALIZED CALLBACK", status),
        });
      };

      btn.addEventListener("click", openWidget);
    </script>
  </body>

2. Example: integrating into a React app via the npm package

  1. Install the npm package kyc-widget-nv: npm i kyc-widget-nv.
  2. Import it into your app: import { KycWidget } from "kyc-widget-nv".
  3. Set up a state variable to control the widget’s visibility.
  4. Pass props to the KycWidget component (see “Configuration parameters” above).

The package does not bundle React — react and react-dom must be installed in your app.

File: App.js

import { useState } from "react";
import { KycWidget } from "kyc-widget-nv";

function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button onClick={() => setIsOpen(true)}>Open</button>

      <KycWidget
        scenarioId="scenarioId"
        clientKey="clientKey"
        clientUser="clientUser"
        isOpen={isOpen}
        stickySession={true}
        theme="light"
        topOffset={0}
        bottomOffset={0}
        closeCb={() => setIsOpen(false)}
        successCb={(sessionJson) => console.log("SUCCESS CALLBACK", sessionJson)}
        finalizedCb={({ status }) => console.log("FINALIZED CALLBACK", status)}
      />

    </>
  );
}

export default App;

3. Example: integrating into a React app via a script tag

Use this approach if you can’t install the npm package and need to load the widget via a script tag.

  1. Load the widget script dynamically in useEffect.
  2. Track the loading state with useState.
  3. Show the button only after the script has loaded.
  4. Call window.KYCWidget.setupKYC() on button click.

File: App.js

import { useState, useEffect, useCallback } from "react";

function App() {
  const [widgetLoaded, setWidgetLoaded] = useState(false);

  const openWidgetHandler = () => {
    window.KYCWidget.setupKYC({
      scenarioId: "scenarioId",
      clientKey: "clientKey",
      clientUser: "clientUser",
      theme: "light",
      topOffset: 0,
      bottomOffset: 0,
      // Optional. If set, the widget is mounted INSIDE the element
      // with this id (inline block) instead of over the whole page. The
      // element must exist in the DOM. On close, the element is cleared.
      // ⚠️ Do not open the host page inside a cross-origin <iframe> —
      // the browser will block getUserMedia and the camera won't start.
      // mountElementId: "kyc-here",
      closeCb: () => console.log("CLOSE CALLBACK"),
      successCb: (sessionJson) => console.log("SUCCESS CALLBACK", sessionJson),
      finalizedCb: ({ status }) => console.log("FINALIZED CALLBACK", status),
    });
  };

  const loadWidgetScript = useCallback(() => {
    const widgetScript = document.getElementById("kyc-widget-script");
    if (widgetScript) return;

    const script = document.createElement("script");
    script.id = "kyc-widget-script";
    script.src = 'https://kyc.neuro-vision.ru/lib/widget-lib.js';
    script.defer = true;
    script.crossOrigin = "anonymous";

    script.onload = () => {
      setWidgetLoaded(true);
    };

    script.onerror = () => {
      console.error("Failed to load the KYC widget script");
    };

    document.head.appendChild(script);
  }, []);

  useEffect(() => {
    if (window.KYCWidget) {
      setWidgetLoaded(true);
      return;
    }

    loadWidgetScript();
  }, [loadWidgetScript]);

  return (
    <>
      {widgetLoaded && (
        <button onClick={openWidgetHandler}>Open KYC widget</button>
      )}
    </>
  );
}

export default App;

4. Verification via a link

To go through verification, you can use the https://kyc.neuro-vision.ru service directly.

Opening a link of the following form creates a session:

  https://kyc.neuro-vision.ru/scenarioId/encrypted(clientKey)
  https://kyc.neuro-vision.ru/scenarioId/encrypted(clientKey)/clientUser
  • scenarioId: unique scenario identifier; obtain it in the dashboard under “KYC/AML”.
  • clientKey: unique string (max 36 characters) that is passed encrypted; sample encryption code is available in the dashboard under “KYC/AML”. The encrypted key is base64 (it may contain / and +), so it must be URL-encoded when building the link.
  • clientUser: optional. Client-side user identifier, max 36 characters. It doesn’t have to be unique — pass the same value across different sessions so you can later find all sessions (attempts) for that user.

For verification tasks created in advance via the API, use the task link:

  https://kyc.neuro-vision.ru/taskId
  https://kyc.neuro-vision.ru/taskId/cu/clientUser