Loading...
Loading...
Add Sumsub Device Intelligence (the Fisherman module) to a web project that already verifies users with the Sumsub WebSDK. TRIGGER when the user asks to "add device intelligence", "enable device capture / fingerprinting in the WebSDK", "turn on Fisherman", "detect device fraud / multi-accounting in the verification flow", or asks how device risk labels get onto an applicant verified through the WebSDK. Covers the whole loop — enabling Capture device data on the level, the automatic in-SDK Fisherman lifecycle, the advanced self-rendered wiring, reading device signals (Devices tab, Device Check, risk labels, webhooks), sandbox testing, go-live checklist. SKIP for device intelligence on pages with NO WebSDK widget (login / signup / checkout) — use `sumsub-integrate-dint-standalone`; SKIP for the base WebSDK embed itself — use `sumsub-integrate-websdk`.
npx skill4agent add sumsub/agent-skills sumsub-integrate-dint-websdk@sumsub/fishermansbx:sumsub-api-auth ┌───────────────────────────────┐ ← one-time, in the dashboard
│ 1. "Capture device data" on │ (verification level settings)
│ on the verification level │
└───────────────┬───────────────┘
│
┌───────────────▼───────────────┐ ← your existing sumsub-integrate-websdk
│ 2. WebSDK launches as usual │ code. NOTHING new on the frontend.
│ (same access token) │
└───────────────┬───────────────┘
│ the SDK auto-inits Fisherman with that token,
│ fingerprints the device, attaches it to the applicant
┌───────────────▼───────────────┐ ┌─────────────────────────────────┐
│ 3. Sumsub computes device │─▶│ Device risk labels on the │
│ signals + risk labels │ │ applicant; feed risk scoring │
└───────────────┬───────────────┘ └─────────────────────────────────┘
│
┌───────────────▼───────────────┐ ← server reads the applicant /
│ 4. You read the verdict + │ receives the webhook (same as
│ device signals server-side │ the base WebSDK flow)
└────────────────────────────────┘sumsub-integrate-websdk(applicantId, attemptId)attemptId/di/info/bhv/...X-External-Device-FingerprintsnsWebSdkexamples/fisherman-self-render.ts// Shape only — the full impl (single-active-session class, attemptId re-init,
// try/catch fail-open, header forwarding) is in examples/fisherman-self-render.ts.
import { init, destroy, type Fisherman } from '@sumsub/fisherman'
let fisherman: Fisherman | undefined // module-level singleton
// init once with the SDK access token + region API host
fisherman = await init({ token, baseUrl, onError: () => { destroy() /* re-init after token refresh */ } })
// on each step transition — gate, then fingerprint bound to (applicantId, attemptId)
if (fisherman?.isDeviceIntelligenceEnabled) {
const { visitorId } = await fisherman.fingerprint({
linkedId: applicantId,
deviceBindingId: `${applicantId}-${attemptId}`, // MUST change per level
})
// forward visitorId as the X-External-Device-Fingerprint header on the API calls that follow
}init()config.deviceIntelligenceSettings.enabledinit()fingerprint()fisherman.isDeviceIntelligenceEnabled/di/infoattemptIddestroy()init()fingerprint()visitorIdX-External-Device-FingerprintdeviceBindingIdapplicantId-attemptIdapplicantReviewedreviewResultexternalUserIdUSER_ID="<your-externalUserId>" # for a Sumsub applicant id instead: /resources/applicants/<applicantId>/one
PATH_Q="/resources/applicants/-;externalUserId=${USER_ID}/one"
TS=$(date -u +%s)
SIG=$(printf '%s%s%s' "$TS" "GET" "$PATH_Q" \
| openssl dgst -sha256 -hmac "$SUMSUB_SECRET_KEY" -hex | awk '{print $NF}')
curl -sS --fail-with-body -H "X-App-Token: $SUMSUB_APP_TOKEN" -H "X-App-Access-Ts: $TS" \
-H "X-App-Access-Sig: $SIG" -H "X-Agent-Source: sumsub-skills" \
-H "X-Agent-Source-Ver: 1.2.0" \
"https://api.sumsub.com${PATH_Q}"examples/read-device-results.shreferences/device-signals.mdsimulationConfigFpSimulationConfinitreferences/device-signals.mdisDeviceIntelligenceEnabledattemptIdX-External-Device-Fingerprintsumsub-integrate-websdksumsub-integrate-dint-standalonesumsub-api-authreferences/device-signals.mdexamples/fisherman-self-render.tsexamples/read-device-results.sh