Skip to main content

KYC / Identity Verification

KYC API calls are expensive (often 0.500.50–5 per verification). Fraudsters deliberately submit stolen documents or fake identities. Use ShieldLabs to gate KYC access and reduce wasted verification attempts.

Why score before KYC

A session with Score >= 70 is very likely automated or using an anti-detect browser. Submitting KYC from such a session is:
  • Almost never a legitimate user
  • Often a fraudster testing document validity
  • Consuming your KYC provider quota

Flow

User clicks "Verify Identity"
  → force check runs (fresh score)
  → Score < 40: show KYC form
  → Score 40–69: require additional step (email confirmation, CAPTCHA)
  → Score 70+: block KYC — show manual review message

Implementation

<!-- kyc-start.html -->
<script type="module">
  const mod = await import('https://cdn.shieldlabs.ai/snippet.js?publicKey=YOUR_PUBLIC_KEY');
  mod.forceCheckAuthenticatedUser(USER_HASHED_ID, (ip, requestId) => {
    document.getElementById('shield-rid').value = requestId;
  });
</script>

<form action="/api/kyc/start" method="POST">
  <input type="hidden" id="shield-rid" name="shieldRequestId">
  <button type="submit">Start Verification</button>
</form>
app.post('/api/kyc/start', async (req, res) => {
  const { shieldRequestId, userId } = req.body;
  const shield = await waitForScore(shieldRequestId, 3000);
  const score = shield?.score ?? 0;

  await db.kycAttempts.create({
    userId,
    score,
    signals: shield?.signals,
    requestId: shieldRequestId,
    ip: shield?.ip,
  });

  if (score >= 70) {
    return res.status(403).json({
      error: 'Verification unavailable. Please contact support.',
    });
  }

  if (score >= 40) {
    // Require email verification before KYC
    await sendKycEmailChallenge(userId);
    return res.json({ requiresEmailVerification: true });
  }

  // Issue a short-lived KYC session token
  const kycToken = await issueKycToken(userId);
  return res.json({ kycToken });
});

Signals most relevant for KYC fraud

SignalRisk for KYC
Fail by * os detectAnti-detect browser — document farm
Is proxy / Is datacenterAutomated submission service
Stun is not checkedHeadless browser
Is abuserIP known for fraud

Logging for compliance

Log all KYC attempts with Shield data for audit trails:
await db.kycAttempts.create({
  userId,
  timestamp:      new Date(),
  shieldScore:    score,
  shieldSignals:  JSON.stringify(shield?.signals),
  shieldIp:       shield?.ip,
  shieldDeviceId: shield?.deviceId,  // from webhook Data.DeviceID
  shieldCountry:  shield?.country,
  allowed:        score < 40,
});