跳轉到主要內容

Web SDK

Drop-in verification flow for web apps. Modal or new-tab presentation, full TypeScript types, no peer dependencies. Requires a one-time session token from your backend.

About this SDK

The Width Web SDK is a drop-in verification experience for KYC, KYB, and one-off liveness in your web app. ESM build, full TypeScript types, no peer dependencies.

FeatureSupported
KYC✓
KYB✓
One-off liveness✓
TypeScript types✓

1. Generate an access token (backend)

Call sdk.credentials from your server using the OpenAPI signing scheme:

POST {WIDTH_GATEWAY_URL}/gateway?api=sdk.credentials&apiVersion=1.0.0&apiKey={your_apiKey}&sign=...
Content-Type: application/json

{}
{
  "apiCode": 200,
  "apiMsg": "OK",
  "data": {
    "data": {
      "sdkToken": "eyJhbGciOi...",
      "domains": [
        { "code": "DEFAULT", "name": "Default", "id": "dom_xxxxxxxx" }
      ]
    }
  }
}
Each sdkToken is single-use. Reissue a new token whenever a user starts a new verification.

2. Install the SDK

# Production
npm install @width-com/web-sdk
# or
pnpm add @width-com/web-sdk
# or
yarn add @width-com/web-sdk

# Platform (testing)
npm install @width-com/web-sdk@beta
# or
pnpm add @width-com/web-sdk@beta
# or
yarn add @width-com/web-sdk@beta

The tag you install also selects the environment the SDK connects to: the default (latest) release targets production, and the @beta tag targets the platform (testing) environment. The target is compiled into the package and cannot be changed at runtime, so install the tag that matches the environment your apiKey belongs to. A mismatch is not a silent failure: the verification page will render Invalid apiKey even though the same key works against the backend API.

3. Initialize

import { widthWebSdk } from '@width-com/web-sdk';

const { sdkToken, domainId } =
  await fetch('/your-backend/sdk-token').then(r => r.json());

widthWebSdk
  .init(sdkToken)
  .withConf({
    apiKey:     'ak_your_public_api_key',
    domainId,
    email:      'enduser@example.com',
    customerId: 'cust_internal_id',
    mode:       'modal',
  })
  .on('idCheck.onApplicantVerificationCompleted', (payload) => {
    // handle the outcome
  })
  .build()
  .launch();

Three things to note:

4. Handle the result

widthWebSdk
  .init(sdkToken)
  .withConf({ /* ... */ })
  .on('idCheck.onApplicantVerificationCompleted', (payload) => {
    // payload.reviewResult.reviewAnswer carries the outcome
  })
  .on('idCheck.onError', (payload) => {
    // payload.code, payload.error
  })
  .build()
  .launch();

// Or take every event through a single handler:
//   .onMessage((type, payload) => { ... })

The SDK does not throw. Every error is delivered through idCheck.onError as { code, error }, and launch() returns an empty string instead of a session value.

Launch options

Required (inside withConf)

ParameterTypeDescription
apiKeystringYour Width public API Key (ak_...)
domainIdstringBusiness unit ID
emailstringApplicant email
customerIdstringYour internal user ID

Optional

ParameterTypeDefaultDescription
mode'modal' | 'newtab' | 'inline''modal'UI presentation. inline fills the viewport with no overlay and no close button
language'en' | 'zh''en'UI language. Browser language is no longer auto-detected
zIndexnumber9999Modal stacking order
eventType'KYC_EVENT' | 'KYB_EVENT'—Names the verification type outright; omit to keep the existing routing

Methods

MethodPurpose
widthWebSdk.init(accessToken)Start configuring with the session token; returns a builder
.withConf(conf)Supply the configuration
.on(eventName, callback)Subscribe to one event
.onMessage(callback)Take every event through one handler
.build()Produce the instance
instance.launch()Start verification; returns a non-empty session string, or an empty string on failure
instance.close()Close the verification window
WidthWebSDK.openLiveness(options)Launch one-off liveness

Events

EventFires when
idCheck.onApplicantVerificationCompletedVerification finishes and an outcome is available
idCheck.onApplicantSubmittedThe applicant has submitted their documents
idCheck.onApplicantStatusChangedThe applicant's status changes
idCheck.onErrorSomething fails. The SDK does not throw; errors come through here

openLiveness

const livenessToken = new URLSearchParams(window.location.search).get('token');
const { sdkToken, domainId } =
  await fetch('/your-backend/sdk-token').then(r => r.json());

WidthWebSDK.openLiveness({
  apiKey:        'ak_your_public_api_key',
  appToken:      sdkToken,
  livenessToken,
  domainId,
  mode:          'modal',
  onResult:      handleVerificationResult,
});

Verification result

type VerificationResult =
  | { type: 'COMPLETED'; executionId: string; decision: 'APPROVED' | 'REJECTED' }
  | { type: 'WAITING';   executionId: string }
  | { type: 'FAILED';    code: VerificationErrorCode; message: string; executionId?: string }
  | { type: 'CANCELLED' };

type VerificationErrorCode = 'INVALID_INPUT' | 'SDK_ERROR' | 'WORKFLOW_FAILED';
程式碼含義Retryable
INVALID_INPUTLaunch parameter issueNo — fix code
SDK_ERRORNetwork / runtime errorYes — retry
WORKFLOW_FAILEDNon-success workflow stateNo — contact support

Browser support

PlatformMinimum
Chrome / Edge92+
Firefox95+
Safari (desktop & iOS)15.4+
Chrome (Android)92+

The SDK relies on crypto.randomUUID, ES2020 syntax, and modern fetch + postMessage. Older browsers are not supported.

CSP 與許可權策略

Content-Security-Policy: frame-src https://<width-verify-origin>;
Permissions-Policy: camera=(self "https://<width-verify-origin>"),
                    microphone=(self "https://<width-verify-origin>"),
                    accelerometer=(self "https://<width-verify-origin>"),
                    gyroscope=(self "https://<width-verify-origin>")

In the Width Admin Console, add your domain under SSO & Integration → API Keys & Webhooks → Web SDK Settings → Allowed Origins.

Troubleshooting

SymptomCauseResolution
Verification page shows Invalid apiKeyThe installed build and the key belong to different environmentsReinstall for the right environment: default release for production, @beta for platform
apiKey is required.Missing apiKeyPass the public API Key
accessToken is required.No session token passed to init()Check the sdk.credentials integration
domainId is required.Missing domainIdPass the business unit ID returned with the token
email is required.Missing emailBoth email and customerId are now required
customerId is required.Missing customerIdPass your internal user ID
email format is invalid.Invalid formatValidate in your form first
apiKey / accessToken mismatchDifferent apps / tenantsReissue the token with the same key
SDK_ERRORNetwork issueRetry launch()
Modal won't appearDomain not allowlisted / bad CSPAdd domain, update CSP
Camera deniedStrict Permissions-PolicyUpdate policy headers
idCheck.* handler never firesSession ongoing, or the handler was registered after build()Wait, or subscribe before calling build()

If the same key works against the backend API and only the SDK reports Invalid apiKey, the install is on the wrong environment rather than the key being at fault. The Web SDK takes the same apiKey that signs the sdk.credentials request; withConf accepts no second key.