跳转到主要内容

Web SDK 集成指南

文档对应版本。Web SDK 1.0.1(默认标签)/ 1.0.0-beta.3(@beta)。本页依据更新日期为 2026 年 9 月 11 日的 WIDTH 集成指南。部署前请确认所选 SDK 构建版本及其目标环境。

概述

Width Web SDK 为 Web 应用提供即插即用的身份验证流程。支持 KYC 和 KYB 工作流,包括证件采集、活体检测与审核。SDK 自托管:你引入一个包,用链式调用配置它,再调用 launch() — SDK 会自行弹出弹窗或打开新标签页,并通过事件回报结果。无需提供 DOM 容器。它以 ESM 构建发布,自带完整 TypeScript 类型定义,无 peer 依赖。

系统要求

要求 最低版本
模块格式 ESM(import 引入)
TypeScript 自带类型定义(可选)
Peer 依赖 无
后端 需通过 sdk.credentials 签发会话 token

步骤 1:获取会话 token(后端)

Web SDK 从一个一次性会话 token(即 sdkToken)开始。你的服务端向 Width 的 sdk.credentials 接口请求它,再把它交给浏览器。公开的 apiKey 与 domainId 在后续步骤中配置;带密钥的签名只在你的服务端完成。

// Server-side request to Width (signed with your secret)
POST {WIDTH_GATEWAY_URL}/gateway?api=sdk.credentials&apiVersion=1.0.0&apiKey={your_apiKey}&sign=...
Content-Type: application/json

{}
// Response — read sdkToken and the domains[] list
{
  "apiCode": 200,
  "apiMsg": "OK",
  "data": {
    "data": {
      "sdkToken": "eyJhbGciOi...",
      "domains": [
        { "code": "DEFAULT", "name": "Default", "id": "dom_xxxxxxxx" }
      ]
    }
  }
}

在后端开一个小接口(例如 /your-backend/sdk-token),把 sdkToken 和 domainId 返回给前端。把从 domains[] 中选定的 domainId 在步骤 3 传入 SDK 配置。

每个 token 仅一次性使用 每个 sdkToken 仅可使用一次。每当用户开始一次新的验证时,都要重新签发一个新 token — 不要缓存或复用。
sdk.credentials 调用使用与其他 API 相同的网关基址及 HMAC 签名,详见 OpenAPI 参考。

步骤 2:安装 SDK

从 npm 安装。安装后即可按包名 @width-com/web-sdk 引入 — ESM 构建,自带 TypeScript 类型定义,无 peer 依赖。装哪个标签同时决定 SDK 连到哪个环境:按本指南基准,默认(latest)版对应正式环境,@beta 标签版对应 platform(测试)环境。请按你的 apiKey 所属环境选择对应标签,并在上线前确认你装的这一版实际打开的是哪个地址(见下方提示)。

# Production (正式环境)
npm install @width-com/web-sdk
# or
pnpm add @width-com/web-sdk
# or
yarn add @width-com/web-sdk

# Testing / beta (测试环境)
npm install @width-com/web-sdk@beta
# or
pnpm add @width-com/web-sdk@beta
# or
yarn add @width-com/web-sdk@beta
标签决定环境 — 装错会看到 Invalid apiKey 验证页地址是随每个发布版本编译进包里的,装好之后连哪个环境就定死了,withConf 里也没有任何字段能改它。按本指南基准,默认(latest)版打开的是 https://identity.width.com/sdk-page(正式环境),@beta 版打开的是 https://identity-platform.width.com/sdk-page(platform 环境)— 这个对应关系取决于两个标签本指南记录的各自指向哪个构建,是当下的状态、不是固定规则,上线前请自行确认你装的这一版实际打开的是哪个地址。如果标签与你 apiKey 所属的环境对不上,这个页面会直接显示 Invalid apiKey,流程就停在这里 — 用同一把 key 调用后端 OpenAPI 不受影响,所以问题不在 key 本身。按环境选标签,不要按版本号新旧选。前后端共用一把 key:withConf 里与 key 相关的字段只有 apiKey 一个,它就是你签发 sdk.credentials 时用的那一把 — 包内自带的 TypeScript 类型定义列出了它接受的全部字段。供参考:@beta 在本指南基准中指向 1.0.0-beta.3(2026-08-05 发布),默认版为 1.0.1,两者都含 eventType 与 language。

步骤 3:初始化(快速开始)

用一条链式调用构建验证:init 传入会话 token,withConf 传入配置,用 on / onMessage 订阅事件,再 build().launch()。launch() 会弹出自托管的弹窗或新标签页 — 无需提供 DOM 容器。

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

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

widthWebSdk
  .init(sdkToken)
  .withConf({
    apiKey:     'ak_your_public_api_key', // required
    domainId,                             // required
    email:      'enduser@example.com',    // required
    customerId: 'cust_internal_id',       // required
    mode:       'modal',                  // 'modal' (default) | 'newtab'
    // eventType: 'KYC_EVENT',            // optional — 'KYC_EVENT' | 'KYB_EVENT'; omit for default routing
  })
  .on('idCheck.onApplicantVerificationCompleted', (payload) => {
    // payload.reviewResult.reviewAnswer: 'GREEN' (approved) | 'RED' (not approved)
  })
  .on('idCheck.onApplicantSubmitted', (payload) => {
    // Submitted; async review in progress
  })
  .on('idCheck.onError', (payload) => {
    // payload.code / payload.error
  })
  .onMessage((type, payload) => {
    if (type === 'width.onCancelled') {
      // User closed the flow
    }
  })
  .build()
  .launch();   // self-hosted modal / new tab — no DOM container needed
eventType 与 language 需要 1.0.1 及以上版本 这两个字段自 1.0.1(2026-08-20 发布,即本指南记录的默认 latest 版)起提供,@beta 在本指南基准中指向的 1.0.0-beta.3 同样含有它们 — 也就是说两个环境都能用,标签仍按环境选(见步骤 2)。1.0.0 及更早的正式版不含它们:TypeScript 项目会编译失败,纯 JavaScript 项目则不报错、也不生效。eventType 只接受 KYC_EVENT 或 KYB_EVENT,language 只接受 en 或 zh;两者都是选填,不传即走默认行为。

配置(withConf)

字段 类型 必填 描述
apiKey string 是 公开 Width API Key(ak_...)
domainId string 是 业务域(domain)GID,取自 sdk.credentials 的 domains[]
email string 是 终端用户邮箱
customerId string 是 你的内部用户 ID
mode 'modal' | 'newtab' 否 展示形态,默认 'modal'
language 'en' | 'zh' 否 界面语言。不传该字段时界面为英文;不会按浏览器语言自动判断。自 1.0.1 起提供。
eventType 'KYC_EVENT' | 'KYB_EVENT' 否 这次要跑哪一类流程——个人核验(KYC_EVENT)还是企业核验(KYB_EVENT)。不传该字段时按默认方式路由(见工作流与决策模型)。自 1.0.1 起提供。
zIndex number 否 本指南基准未指定默认值。弹窗层级

步骤 4:处理验证结果

launch() 成功时返回本次会话的完整核验页 URL,失败时返回空字符串。错误通过 idCheck.onError 回传。

按你订阅的事件分支处理。最终结论由 reviewResult.reviewAnswer 携带,只有两个取值:结论为通过时是 GREEN,其余一律是 RED。

.on('idCheck.onApplicantVerificationCompleted', (payload) => {
  const { reviewResult, executionId } = payload;
  if (reviewResult.reviewAnswer === 'GREEN') {
    grantAccess(executionId);
  } else {
    handleNotApproved(executionId);
  }
})

每个事件对应一条处理分支:

事件 处理方式
idCheck.onApplicantVerificationCompleted 已有最终结论 — 读取 reviewAnswer
idCheck.onApplicantSubmitted 已提交;进入异步审核
idCheck.onError 上报失败
width.onCancelled (via onMessage) 用户关闭了流程
对账 executionId 是与后端 / OpenAPI 对账的句柄。对 idCheck.onApplicantSubmitted(异步审核)场景请持久化它,以便服务端稍后轮询最终状态。

验证结果参考

最终结论由 reviewResult.reviewAnswer 携带:

reviewAnswer 含义
GREEN 通过
RED 未通过。SDK 会把「通过」以外的所有结论都映射成 RED——被拒绝的会落在这里,其他非通过的结果同样落在这里。把 RED 当作「已拒绝」处理之前,先查案件状态(workflow.execution.status 返回的 caseStatus,或到控制台看该案件)。
只有两个取值 截至 1.0.1(1.0.0-beta.3 相同),Web SDK 只把结论收成这两个值,没有第三个取值。GREEN 走通过分支;RED 按「未通过」处理,除非案件状态确认它就是拒绝。

方法

调用 返回 作用
widthWebSdk.init(accessToken) builder 用会话 token 开始链式配置
.withConf(conf) builder 提供配置(见「配置」)
.on(eventName, callback) builder 订阅单个事件
.onMessage((type, payload) => {}) builder 用一个处理器接收所有事件
.build() 实例 完成构建
instance.launch(container?) string 启动验证,返回本次会话的整条验证页网址 — 形如 https://identity.width.com/sdk-page?sdkMode=1&sdkSession=<会话 id>&apiKey=<你的 apiKey>&theme=light,其中主机名取自你安装的那一版(见步骤 2)— 启动失败时返回 ''。这条网址对应的就是本次验证会话,它背后的会话 token 仅一次性有效(见步骤 1)。container 被忽略
instance.close() void 主动关闭验证窗口

事件参考

用 .on(eventName, callback) 注册单个事件,或用 .onMessage((type, payload) => {}) 接收全部。

事件 触发时机 载荷
idCheck.onApplicantVerificationCompleted 流程完成、有结论 { reviewStatus: 'completed', reviewResult: { reviewAnswer: 'GREEN' | 'RED' }, executionId }
idCheck.onApplicantStatusChanged 与 Completed(idCheck.onApplicantVerificationCompleted)同时触发{ reviewStatus: 'completed', reviewResult: { reviewAnswer: 'GREEN' | 'RED' }, executionId }
idCheck.onApplicantSubmitted 已提交、异步审核中 { executionId }
idCheck.onError 失败 { code, error, executionId? }
width.onCancelled 用户关闭(仅经 onMessage) {}
错误投递 校验失败与运行时错误统一经 idCheck.onError 投递 — SDK 不会向你的代码抛异常。

错误码

在 idCheck.onError 中,payload.code 为以下之一:

码 含义 可重试
INVALID_INPUT 启动参数缺失或非法 否
SDK_ERROR 网络、超时或内部错误 是
WORKFLOW_FAILED 流程以非成功状态结束 否

浏览器支持

Web SDK 依赖 crypto.randomUUID、ES2020 语法,以及现代的 fetch 与 postMessage。下表是同时具备这三项的最低版本,低于该版本的浏览器不在支持范围内。

浏览器 最低版本
Chrome / Edge(桌面端) 92+
Firefox 95+
Safari(macOS 与 iOS) 15.4+
Chrome(Android) 92+

故障排查

现象 可能原因 解决
onError { INVALID_INPUT, "apiKey is required." } apiKey 缺失或为空 传入公开 API Key
onError { INVALID_INPUT, "accessToken is required." } 后端未返回 sdkToken 检查 sdk.credentials 集成
onError { INVALID_INPUT, "domainId is required." } 初始化时 withConf 未传 domainId 传入你从 sdk.credentials 返回的 domains[] 中选定那个 domain 的 id
onError { INVALID_INPUT, "email is required." } 缺少 email 传入终端用户邮箱
onError { INVALID_INPUT, "customerId is required." } 缺少 customerId 传入内部用户 ID
onError { INVALID_INPUT, "email format is invalid." } 邮箱格式错误 表单先校验
onError { INVALID_INPUT, "apiKey does not match SDK credentials." } apiKey 与 accessToken 不属于同一应用 用同一 apiKey 重新签发 token
onError { SDK_ERROR } 网络 / 连接问题 重新构建链并再次 launch()
弹窗不出现 / iframe 被拦截 域名未加白名单,或 CSP frame-src 缺少该源 在控制台 API & Integration 下把该源加进白名单(见表格下方说明),并在 CSP frame-src 里放行它
相机权限被拒 宿主 Permissions-Policy 过严 更新你的策略头(见下方说明)
无事件触发 会话仍在进行,或未注册回调 等待完成;检查 .on() 回调
在控制台把你的站点加进白名单 白名单由你自己在控制台配置:在 API & Integration(API 与集成) 下,把承载 SDK 的每个源逐个加进去。每条地址必须以 https:// 或 http:// 开头、不带路径、也不支持通配符,因此每个主机名都要单独写一条(例如 https://app.example.com 和 https://checkout.example.com)。如果这个页面上看不到生成密钥的按钮,通常是本指南记录的账号的角色缺少管理 API 密钥这条权限 — 这类按钮按权限渲染,没有权限时是直接不显示、而不是变灰,请让租户管理员为你开通。
CSP 与权限策略 在 modal 模式下,SDK 会在你自己的页面里插入一个 iframe 来加载验证页,所以只要你的页面设了 Content-Security-Policy,就必须在 frame-src 里放行这个源,并通过 Permissions-Policy 把相机(以及活体所需的麦克风 / 运动传感器)授权给同一个源。填哪个源取决于你装的是哪个标签(见步骤 2):默认(latest,本指南记录的为 1.0.1)版加载的是 https://identity.width.com,@beta 版加载的是 https://identity-platform.width.com。按你实际上线的那一版选对应的一段 — 源没写进 frame-src,浏览器就会拦掉这个 iframe,验证窗口只剩空白。
# Default (latest) build / 默认(latest)版
Content-Security-Policy: frame-src https://identity.width.com;
Permissions-Policy: camera=(self "https://identity.width.com"),
                    microphone=(self "https://identity.width.com"),
                    accelerometer=(self "https://identity.width.com"),
                    gyroscope=(self "https://identity.width.com")
# @beta build / @beta 版
Content-Security-Policy: frame-src https://identity-platform.width.com;
Permissions-Policy: camera=(self "https://identity-platform.width.com"),
                    microphone=(self "https://identity-platform.width.com"),
                    accelerometer=(self "https://identity-platform.width.com"),
                    gyroscope=(self "https://identity-platform.width.com")