Web 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 配置。
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 neededeventType 與 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() 回調
|
https:// 或 http://
開頭、不帶路徑、也不支持通配符,因此每個主機名都要單獨寫一條(例如
https://app.example.com 和
https://checkout.example.com)。如果這個頁面上看不到生成密鑰的按鈕,通常是本指南記錄的賬號的角色缺少管理
API 密鑰這條權限 —
這類按鈕按權限渲染,沒有權限時是直接不顯示、而不是變灰,請讓租戶管理員爲你開通。
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")