Development of Crypto-casino Player Verification System
Crypto casinos operate under dual pressure: on one hand — users valuing anonymity and coming to Web3 for it; on the other — regulators and payment partners requiring KYC, AML screening and age verification. Finding balance between these requirements — architectural task, not just legal.
Verification Levels
Not all users require same verification. Tiered approach — standard for gambling platforms:
Tier 0 — minimal (up to $500/month): email, wallet connection, auto AML screening of address (Chainalysis or Elliptic). No documents, instant response.
Tier 1 — basic (up to $5,000/month): name + date of birth + country of residence. Automatic check via sanctions lists. Account confirmation via email or SMS.
Tier 2 — extended (up to $50,000/month): Government ID (passport, Driver's License), liveness check (selfie with document), proof of residence (utility bill). Verifier: Sumsub, Onfido, or similar.
Tier 3 — enhanced due diligence (> $50,000/month or VIP): Source of Funds (where money from), Source of Wealth, extended PEP/Sanctions check, manual review by compliance officer.
Technical KYC Integration
Sumsub — Standard Choice for Gambling
Sumsub provides SDK for web and mobile, WebSDK for embedded flow:
// Generate SDK token on backend
async function getSumsubToken(applicantId: string): Promise<string> {
const timestamp = Math.floor(Date.now() / 1000);
const method = 'POST';
const url = `/resources/accessTokens?userId=${applicantId}&levelName=basic-kyc-level`;
const signature = crypto
.createHmac('sha256', SUMSUB_SECRET_KEY)
.update(timestamp + method + url)
.digest('hex');
const response = await axios.post(
`https://api.sumsub.com${url}`,
{},
{
headers: {
'X-App-Token': SUMSUB_APP_TOKEN,
'X-App-Access-Sig': signature,
'X-App-Access-Ts': timestamp,
}
}
);
return response.data.token;
}
// Frontend SDK initialization
import SumsubWebSdk from "@sumsub/websdk";
const sdk = SumsubWebSdk.init(
accessToken,
() => refreshToken(), // callback to refresh token
{
lang: "en",
onMessage: (type, payload) => {
if (type === "idCheck.onApplicantStatusChanged") {
if (payload.reviewResult?.reviewAnswer === "GREEN") {
handleKYCApproved(payload.applicantId);
}
}
},
onError: (error) => console.error("Sumsub error:", error),
}
);
sdk.launch("#sumsub-container");
Webhook Processing Results
Sumsub sends webhook on status change. Important — verify webhook signature to not accept fake callback:
function verifySumsubWebhook(req: Request): boolean {
const signature = req.headers['x-payload-digest'];
const secret = process.env.SUMSUB_WEBHOOK_SECRET;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(req.rawBody) // raw body, not parsed JSON
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
async function handleSumsubWebhook(payload: SumsubWebhookPayload) {
const { applicantId, reviewResult, type } = payload;
if (type === "applicantReviewed") {
if (reviewResult.reviewAnswer === "GREEN") {
await db.updateUserKYCStatus(applicantId, "APPROVED", reviewResult.reviewRejectType);
await updateUserTier(applicantId);
} else if (reviewResult.reviewAnswer === "RED") {
await db.updateUserKYCStatus(applicantId, "REJECTED", reviewResult.moderationComment);
await notifyUser(applicantId, "kyc_rejected");
}
}
}
AML Screening of Crypto Transactions
Particularly critical for casinos: money from darknet markets, stolen funds — direct platform responsibility.
Chainalysis KYT (Know Your Transaction) Integration
async function screenAddress(address: string, asset: string): Promise<RiskScore> {
const response = await chainalysisClient.post('/v1/users', {
userId: address,
});
const transferResponse = await chainalysisClient.post('/v1/transfers', {
network: asset,
asset: asset,
transferReference: address,
direction: 'received',
});
return {
riskScore: transferResponse.data.riskScore,
cluster: transferResponse.data.cluster?.name,
category: transferResponse.data.cluster?.category,
};
}
Risk categories for automatic blocking: darknet market, stolen funds, ransomware, sanctions. For such addresses — automatic deposit rejection and account freeze without manual review.
Grey zone categories (gambling, P2P exchange, mixing): require manual review by compliance officer, not automatic block.
OFAC Sanctions Screening
Separate from crypto screening — check wallet addresses in OFAC SDN List. Chainalysis does this automatically, but for additional protection:
// Periodically updated list of OFAC addresses
const ofacAddresses = new Set(await fetchOFACList());
function isOFACSanctioned(address: string): boolean {
return ofacAddresses.has(address.toLowerCase());
}
Age Verification Without Documents
For markets where documentary KYC unacceptable (or pre-KYC tier), but need age check:
Yoti Age Verification — service verifying age without transmitting document details to casino. User undergoes verification at Yoti, gets signed age token. Casino sees only "over 18" — without name, photo, document number.
AgeID (UK standard) — similar approach, used by British gambling operators.
Integration: OAuth 2.0 flow, Yoti acts as identity provider. Casino receives ID Token with claim over_18: true, without PII.
Geoblocking and IP Verification
KYC doesn't replace geoblocking. Mandatory checks:
async function checkPlayerEligibility(ip: string, walletAddress: string): Promise<EligibilityResult> {
// IP geolocation
const geoResult = await maxmindClient.country(ip);
const country = geoResult.country.isoCode;
if (BLOCKED_COUNTRIES.includes(country)) {
return { allowed: false, reason: 'geo_blocked', country };
}
// VPN/Proxy detection
const ipRisk = await ipqualityscore.check(ip);
if (ipRisk.vpn || ipRisk.proxy || ipRisk.tor) {
return { allowed: false, reason: 'vpn_detected' };
}
return { allowed: true, country };
}
Blocked country lists determined by license: Curacao, Malta, Estonia — each license has its own restricted jurisdictions list.
Responsible Gambling Features
Licensed casinos must implement:
- Self-exclusion: user can block own account for period (1 day to permanent). After activation — immediate logout, re-registration block.
- Deposit limits: daily/weekly/monthly limits. Can decrease immediately, increase — only through cooling-off period (24-72 hours).
- Reality check: popup notification about time and loss amount every N minutes.
- Cooling-off period: temporary pause without full self-exclusion.
Stack and Architecture
| Component | Solution | Note |
|---|---|---|
| KYC provider | Sumsub / Onfido | Sumsub better for WW coverage |
| AML on-chain | Chainalysis KYT | or Elliptic, Crystal Blockchain |
| Age verification | Yoti / AgeID | for soft-KYC markets |
| Geo/IP check | MaxMind + IPQualityScore | two providers for reliability |
| OFAC/Sanctions | Chainalysis + own list | daily update |
| Document storage | Encrypted S3 + key management | retention policy by regulation |
Development Timeline
| Component | Timeline |
|---|---|
| KYC tier system + Sumsub integration | 2-3 weeks |
| AML screening + webhook processing | 1-2 weeks |
| Geoblocking + IP checks | 1 week |
| Responsible gambling features | 1-2 weeks |
| Admin dashboard for compliance | 1-2 weeks |
Full compliance system under specific license — 6-10 weeks. Cost depends on chosen providers and customization volume.







