From 673629ef29d5e8e147e62cfc779fd4c2e2c7de90 Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 2 Sep 2026 11:24:54 -0700 Subject: [PATCH 1/4] docs: document selfie check 4.0 --- openapi/developer-portal.json | 90 ++++++++++++++++++++++- snippets/idkit-response.mdx | 28 +++++++ world-id/SKILL.md | 28 ++++--- world-id/credentials/11.mdx | 38 +++++++--- world-id/idkit/credentials.mdx | 72 ++++++++++++++---- world-id/idkit/integrate.mdx | 5 ++ world-id/idkit/javascript.mdx | 22 ++++-- world-id/idkit/kotlin.mdx | 26 +++++++ world-id/idkit/mini-apps.mdx | 2 +- world-id/idkit/react.mdx | 17 +++-- world-id/idkit/swift.mdx | 26 +++++-- world-id/idkit/verification-flows.mdx | 2 +- world-id/overview.mdx | 2 +- world-id/sandbox/testing-selfie-check.mdx | 11 +-- 14 files changed, 298 insertions(+), 71 deletions(-) diff --git a/openapi/developer-portal.json b/openapi/developer-portal.json index 8acb393..3c5bc93 100644 --- a/openapi/developer-portal.json +++ b/openapi/developer-portal.json @@ -742,6 +742,32 @@ ] } }, + "selfie_check_v4": { + "summary": "Selfie Check (protocol 4.0)", + "value": { + "protocol_version": "4.0", + "nonce": "0xabc123", + "action": "selfie-check-2026-09-02", + "integrity_bundle": { + "version": 2, + "signature_format": "apple_app_attest", + "timestamp": 1788302923, + "signature": "a1b2c3d4", + "jwt": "eyJ..." + }, + "responses": [ + { + "identifier": "selfie", + "issuer_schema_id": 11, + "nullifier": "0x2bf8406809dcefb1486dadc96c0a897db9bab002053054cf64272db512c6fbd8", + "expires_at_min": 1788302888, + "proof": ["0x111", "0x222", "0x333", "0x444", "0x555"], + "signal_hash": "0x0", + "sybil_score": 10 + } + ] + } + }, "session_v4": { "summary": "Session proof (protocol 4.0)", "value": { @@ -861,7 +887,7 @@ "device", "selfie" ], - "description": "The legacy verification level. Use `selfie` for Selfie Check (Beta). The historical `face` value remains accepted for backward compatibility and behaves the same as `selfie`." + "description": "The legacy verification level. Use `selfie` for Selfie Check. The historical `face` value remains accepted for backward compatibility and behaves the same as `selfie`." }, "action": { "type": "string", @@ -1250,6 +1276,33 @@ "additionalProperties": true, "description": "Pass-through GraphQL response. Usually includes `data` and optionally `errors`." }, + "IntegrityBundle": { + "type": "object", + "required": ["version", "signature_format", "timestamp", "signature", "jwt"], + "description": "World ID App integrity attestation. Selfie Check 4.0 requires version 2, which covers the disclosed `sybil_score`.", + "properties": { + "version": { + "type": "integer", + "enum": [1, 2] + }, + "signature_format": { + "type": "string", + "enum": ["apple_app_attest", "android_keystore"] + }, + "timestamp": { + "type": "integer", + "minimum": 0 + }, + "signature": { + "type": "string", + "description": "Hex-encoded device signature." + }, + "jwt": { + "type": "string", + "description": "Attestation Gateway JWT used to verify the signing key." + } + } + }, "VerifyV4Request": { "description": "Choose one request type.", "oneOf": [ @@ -1303,6 +1356,9 @@ "enum": ["production", "staging"], "default": "production" }, + "integrity_bundle": { + "$ref": "#/components/schemas/IntegrityBundle" + }, "responses": { "type": "array", "minItems": 1, @@ -1337,9 +1393,17 @@ }, "environment": { "type": "string", - "enum": ["production", "staging"], + "enum": ["production", "staging", "sandbox"], "default": "production" }, + "integrity_bundle": { + "description": "Required with version 2 when any response item is a Selfie Check credential (`issuer_schema_id: 11`).", + "allOf": [ + { + "$ref": "#/components/schemas/IntegrityBundle" + } + ] + }, "responses": { "type": "array", "minItems": 1, @@ -1373,9 +1437,17 @@ }, "environment": { "type": "string", - "enum": ["production", "staging"], + "enum": ["production", "staging", "sandbox"], "default": "production" }, + "integrity_bundle": { + "description": "Required with version 2 when any response item is a Selfie Check credential (`issuer_schema_id: 11`).", + "allOf": [ + { + "$ref": "#/components/schemas/IntegrityBundle" + } + ] + }, "responses": { "type": "array", "minItems": 1, @@ -1395,7 +1467,7 @@ "properties": { "identifier": { "type": "string", - "description": "Credential identifier returned by IDKit (for example, `orb` or `selfie`). Use `selfie` for Selfie Check (Beta); the historical `face` value remains accepted as a backward-compatible alias." + "description": "Credential identifier returned by IDKit (for example, `orb` or `selfie`). Use `selfie` for Selfie Check; the historical `face` value remains accepted as a backward-compatible alias." }, "signal_hash": { "type": "string", @@ -1451,6 +1523,11 @@ "type": "string" }, "description": "Exactly 5 hex elements (4 compressed proof elements + Merkle root)." + }, + "sybil_score": { + "type": "integer", + "minimum": 0, + "description": "Selfie Check z-score decoded to an integer. Required only when `issuer_schema_id` is 11. Higher values indicate a stronger potential duplicate signal; this is not a probability or match count." } } }, @@ -1493,6 +1570,11 @@ "items": { "type": "string" } + }, + "sybil_score": { + "type": "integer", + "minimum": 0, + "description": "Selfie Check z-score decoded to an integer. Required only when `issuer_schema_id` is 11." } } }, diff --git a/snippets/idkit-response.mdx b/snippets/idkit-response.mdx index 200baa1..578e658 100644 --- a/snippets/idkit-response.mdx +++ b/snippets/idkit-response.mdx @@ -38,6 +38,34 @@ } ``` +```json title="World ID 4.0 Selfie Check" +{ + "protocol_version": "4.0", + "nonce": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "action": "selfie-check-2026-09-02", + "environment": "production", + "integrity_bundle": { + "version": 2, + "signature_format": "apple_app_attest", + "timestamp": 1788302923, + "signature": "a1b2c3d4...device_signature", + "jwt": "eyJ...attestation_jwt" + }, + "responses": [ + { + "identifier": "selfie", + "signal_hash": "0x0", + "proof": ["0x1a2b...", "0x3c4d...", "0x5e6f...", "0x7a8b...", "0x9c0d..."], + "nullifier": "0x04e5f6...rp_scoped_nullifier", + "issuer_schema_id": 11, + "expires_at_min": 1788302888, + "sybil_score": 10 + } + ], + "user_presence_completed": true +} +``` + ```json title="World ID 4.0 Session" { "protocol_version": "4.0", diff --git a/world-id/SKILL.md b/world-id/SKILL.md index 3a66cee..44bb06d 100644 --- a/world-id/SKILL.md +++ b/world-id/SKILL.md @@ -1,7 +1,7 @@ --- name: world-id-integration description: | - Use this skill when adding, upgrading, debugging, or testing World ID verification with IDKit in a new or existing web or mobile app. Covers Proof of Human, passport/document, Selfie Check (Beta), and session/sign-in flows; Developer Portal app, RP, and action setup; server-side signing and proof verification; environment matching; nullifier replay protection; and launch testing. Trigger when the user asks to add World ID, verify humans, stop bots or multi-accounting, add Sybil resistance, or mentions IDKit, Orb, World ID proof flows, World App proof flows, @worldcoin/idkit, signing keys, rp_id, or app_id. + Use this skill when adding, upgrading, debugging, or testing World ID verification with IDKit in a new or existing web or mobile app. Covers Proof of Human, passport/document, Selfie Check, and session/sign-in flows; Developer Portal app, RP, and action setup; server-side signing and proof verification; environment matching; nullifier replay protection; and launch testing. Trigger when the user asks to add World ID, verify humans, stop bots or multi-accounting, add Sybil resistance, or mentions IDKit, Orb, World ID proof flows, World App proof flows, @worldcoin/idkit, signing keys, rp_id, or app_id. version: 0.1.0 metadata: author: worldcoin @@ -38,7 +38,7 @@ Before changing code or creating Portal resources: - target environment and test path: staging simulator, production World ID, or both - Developer Portal MCP connection - whether an RP signing key already exists in a server-side secret store - - requested credential policy, feature access (especially Selfie Check (Beta)), and whether legacy proof fallback is needed + - requested credential policy and whether legacy proof fallback is needed 3. Report a short readiness summary and ask only for unresolved blockers. **Never ask the user to paste a signing key, Portal API key, or other secret into chat.** Ask only whether it exists and where the application expects it. 4. Build a TODO from the missing steps. Preserve working configuration and existing Portal resources unless the user explicitly wants replacements. @@ -99,18 +99,24 @@ The credential decides what the user proves. Nail this down before scaffolding |---|---|---| | **`proofOfHuman`** — Proof of Human (flagship) | The user is a unique person, biometrically verified at an Orb | Sybil resistance, airdrops, one-vote-per-human, gated signups. **The default if the user said "proof of human" or "verify a real human."** | | **`passport`** — Passport | The user holds a valid government passport (NFC-verified) | Higher-assurance flows where you need document-grade identity (regulated apps, age-gating, KYC-adjacent). | -| **`selfieCheckLegacy`** — Selfie Check (Beta) | A liveness selfie signal backed by a World ID 3.0 proof | Lower-assurance "is a human in front of the camera" — friction/bot deterrence without the full Orb requirement. | +| **`selfieCheck`** — Selfie Check | A liveness and facial-similarity credential backed by a World ID 4.0 proof | Medium-assurance friction and bot deterrence without the full Orb requirement. Returns a verified `sybil_score` risk signal. | -**DO NOT default to `proofOfHuman` if the user said "passport" or "verify their ID"** — that's `passport`. **DO NOT default to `proofOfHuman` if the user said "selfie" or "liveness"** — that's `selfieCheckLegacy`. When in doubt, ask one question. +**DO NOT default to `proofOfHuman` if the user said "passport" or "verify their ID"** — that's `passport`. **DO NOT default to `proofOfHuman` if the user said "selfie" or "liveness"** — that's `selfieCheck`. When in doubt, ask one question. -Other legacy presets exist (`documentLegacy`, `deviceLegacy`); reach for them only when the user asks specifically. For sign-in / session reuse across visits, use the v4 **session** flow instead of a uniqueness preset (see the integrate doc). +Other legacy presets exist (`documentLegacy`, `selfieCheckLegacy`, `deviceLegacy`); reach for them only when the user asks specifically. For sign-in / session reuse across visits, use the v4 **session** flow instead of a uniqueness preset (see the integrate doc). -### Selfie Check (Beta) access +### Selfie Check -Before implementing or testing Selfie Check, confirm that its feature flag is -enabled for the target app. If it is not enabled, stop and tell the user to -request access through their World contact or the documented support path. A -valid app or action does not imply Selfie Check access. +Use `selfieCheck`, which requests the World ID 4.0 Selfie Check credential and +always disables legacy proof fallback. Each Selfie Check response includes a +required integer `sybil_score`; forward the complete IDKit result unchanged so +the Developer Portal can verify the proof and version 2 integrity signature +before the app uses the score. + +World ID 4.0 uniqueness proofs are one-time per action for each user. If the +same user needs to complete Selfie Check more than once, use a different action +for each check. Keep the deprecated `selfieCheckLegacy` preset only when +maintaining an existing World ID 3.0 integration. ## Phase 4 — Implement the 6 integration steps and explain the WHY @@ -150,7 +156,7 @@ Do not declare the integration complete from compilation or Portal configuration - [ ] Backend verification succeeds and the exact IDKit result reaches `/api/v4/verify/{rp_id}`. - [ ] The verified nullifier is persisted. - [ ] Replaying the same nullifier is rejected by the database uniqueness constraint. -- [ ] Relevant failures—unavailable Selfie Check, invalid action/signature, or environment mismatch—produce an actionable user-facing error instead of an indefinite loading state. +- [ ] Relevant failures—replayed nullifiers, invalid action/signature, or environment mismatch—produce an actionable user-facing error instead of an indefinite loading state. - [ ] JS/React failures retain the `debugReport` and `request_id` needed for diagnosis without logging secrets. Run automated tests for the routes and persistence behavior. Clearly identify simulator, phone, or production checks that still require the user; never imply a manual proof flow ran when it did not. diff --git a/world-id/credentials/11.mdx b/world-id/credentials/11.mdx index 8e8a2a8..60f53f3 100644 --- a/world-id/credentials/11.mdx +++ b/world-id/credentials/11.mdx @@ -1,5 +1,5 @@ --- -title: "Selfie Check (Beta)" +title: "Selfie Check" icon: "camera" iconType: "duotone" description: "A medium-assurance biometric credential using the device camera for liveness and facial similarity." @@ -10,29 +10,26 @@ description: "A medium-assurance biometric credential using the device camera fo import { CredentialHero } from "/snippets/credential-hero.jsx"; ## Introduction -Selfie Check (Beta) uses the user's mobile device camera for liveness and facial +Selfie Check uses the user's mobile device camera for liveness and facial similarity checks. It adds friction against automated and repeated account creation without requiring a Proof of Human. Unlike high-assurance Orb verification, Selfie Check does not provide a strict one-person-one-account guarantee and is considered a medium-assurance verification method. -It returns a proof of the completed check, not a numeric Sybil or uniqueness -score. -Use Selfie Check (Beta) for: +Use Selfie Check for: * **Liveness detection:** Confirm the user is a real person, not a spoof or injection attack. * **Abuse resistance:** Add friction to automated and repeated account creation. @@ -41,14 +38,31 @@ Use Selfie Check (Beta) for: Selfie Check has a 90-day inactivity window. After 90 days without use, the user completes the camera flow again before returning another proof. +Anyone with World ID App can use Selfie Check. No Orb, passport or +other prerequisite credential is required. + +## Understand the Sybil score + +Each World ID 4.0 Selfie Check response includes `sybil_score`, a non-negative +integer derived from the z-score of the closest face-match signal. A higher value +means the match is more statistically unusual and is a stronger signal that the +person may already be enrolled. The score is not a probability, percentage, or +count of matching accounts. + +Treat `sybil_score` as one input to your abuse policy and choose a threshold that +fits your use case. Only use the score after your backend has forwarded the +complete IDKit result to the [Developer Portal verification endpoint](/api-reference/developer-portal/verify) +and received a successful response. The verifier requires integrity bundle version +2 for Selfie Check and verifies that the score is covered by the World ID App +integrity signature. + - Selfie Check (Beta) is access-gated. To use it, [request access](mailto:developers@toolsforhumanity.com) - so the feature flag can be enabled for your app. + World ID 4.0 uniqueness proofs are one-time per action for each user. If the same + user needs to complete Selfie Check more than once, use a different action for + each check. Reusing the same action produces the same action-scoped nullifier and + cannot be accepted as a new one-time verification. -Once enabled, anyone with World ID App can use Selfie Check. No Orb, passport or -other prerequisite credential is required. - ## How it works Use IDKit to integrate Selfie Check into your application. diff --git a/world-id/idkit/credentials.mdx b/world-id/idkit/credentials.mdx index 7db3ccd..ac6f9ff 100644 --- a/world-id/idkit/credentials.mdx +++ b/world-id/idkit/credentials.mdx @@ -14,7 +14,7 @@ A [Credential](https://docs.rs/world-id-primitives/latest/world_id_primitives/cr | --- | --- | --- | | Proof of Human | The user is a unique human, backed by anonymous biometric verification by the Orb. | `proofOfHuman` | | Passport | The user holds a verified NFC passport credential. | `passport` | -| Selfie Check (Beta) | A medium-assurance biometric credential using the device camera for liveness and facial similarity. | `selfieCheckLegacy` | +| Selfie Check | A medium-assurance biometric credential using the device camera for liveness and facial similarity. | `selfieCheck` | | Identity Check | An attestation that a document-backed property about the user matches your requested attributes. | `identityCheck` with attributes like `minimum_age`, `nationality`, or `document_type`. | You can also add a liveness check to any preset with `require_user_presence`. @@ -25,7 +25,7 @@ You can also add a liveness check to any preset with `require_user_presence`. # SDK presets -Preset helpers cover common credential requests: `proofOfHuman`, `passport`, `selfieCheckLegacy`, `identityCheck`, and the legacy presets. +Preset helpers cover common credential requests: `proofOfHuman`, `passport`, `selfieCheck`, `identityCheck`, and the legacy presets. The snippets below assume `rp_context` was already generated and signed by your backend. See [Integrate IDKit](/world-id/idkit/integrate) for the full RP-signing flow. @@ -103,15 +103,10 @@ const preset = passport({ signal: "user-123" }); ``` -## Selfie Check (Beta) +## Selfie Check - - [Request access](mailto:developers@toolsforhumanity.com) to enable Selfie Check - (Beta) for your app. - - -Once enabled, use `selfieCheckLegacy()` to request Selfie Check. The preset -currently uses World ID 3.0; World ID 4.0 support is not yet available. +Use `selfieCheck()` to request the World ID 4.0 Selfie Check credential. This +preset always disables fallback to legacy proofs. Anyone with World ID App can complete the flow—no Orb or document credential is required. Forward the complete IDKit result to the @@ -119,21 +114,22 @@ required. Forward the complete IDKit result to the ```typescript title="JavaScript" -import { IDKit, selfieCheckLegacy } from "@worldcoin/idkit-core"; +import { IDKit, selfieCheck } from "@worldcoin/idkit-core"; -const preset = selfieCheckLegacy({ signal: "user-123" }); +const preset = selfieCheck({ signal: "user-123" }); const request = await IDKit.request({ app_id: "app_xxxxx", action: "my-action", rp_context, + allow_legacy_proofs: false, }).preset(preset); ``` ```tsx title="React" -import { IDKitRequestWidget, selfieCheckLegacy } from "@worldcoin/idkit"; +import { IDKitRequestWidget, selfieCheck } from "@worldcoin/idkit"; -const preset = selfieCheckLegacy({ signal: "user-123" }); +const preset = selfieCheck({ signal: "user-123" }); { /* ... */ }} @@ -148,6 +145,47 @@ const preset = selfieCheckLegacy({ signal: "user-123" }); ``` +A successful Selfie Check response includes a required `sybil_score` on the +response item with `identifier: "selfie"` and `issuer_schema_id: 11`: + +```json +{ + "protocol_version": "4.0", + "action": "my-action", + "integrity_bundle": { + "version": 2, + "signature_format": "apple_app_attest", + "timestamp": 1788302923, + "signature": "...", + "jwt": "..." + }, + "responses": [ + { + "identifier": "selfie", + "issuer_schema_id": 11, + "nullifier": "0x...", + "proof": ["0x...", "0x...", "0x...", "0x...", "0x..."], + "expires_at_min": 1788302888, + "sybil_score": 10 + } + ] +} +``` + +The integer is derived from the disclosed face-match z-score. Higher values are +a stronger potential duplicate signal; the value is not a probability or a count +of matching accounts. Forward the complete response unchanged and only use +`sybil_score` after the Developer Portal verifies the proof and version 2 integrity +signature. See [Selfie Check](/world-id/credentials/11#understand-the-sybil-score) +for interpretation guidance. + + + If the same user needs to complete Selfie Check more than once, use a different + action for each World ID 4.0 uniqueness proof. Reusing the same action produces + the same action-scoped nullifier and cannot be accepted as a new one-time + verification. + + To test your integration end-to-end, see [Testing Selfie Check in Sandbox](/world-id/sandbox/testing-selfie-check). ## Identity Check (Preview) @@ -278,9 +316,13 @@ These presets only return World ID 3.0 proofs. Use them for existing integration documentLegacy At least a Document verification. Returns the user's highest legacy credential: Document, Secure Document, or Orb. + + selfieCheckLegacy + Deprecated. Returns the World ID 3.0 Selfie Check proof. Keep it only for an existing legacy integration; use selfieCheck for new integrations. + deviceLegacy - Deprecated. Keep deviceLegacy only for existing Device integrations. For new integrations, use Selfie Check (Beta). + Deprecated. Keep deviceLegacy only for existing Device integrations. For new integrations, use Selfie Check. diff --git a/world-id/idkit/integrate.mdx b/world-id/idkit/integrate.mdx index abbef5b..2ede2bc 100644 --- a/world-id/idkit/integrate.mdx +++ b/world-id/idkit/integrate.mdx @@ -313,6 +313,11 @@ forward it directly to `POST https://developer.world.org/api/v4/verify/{rp_id}`. Forward the IDKit result payload as-is. No field remapping is required. +For Selfie Check, only use `responses[].sybil_score` after this endpoint returns +success. Selfie Check responses require integrity bundle version 2, which lets +the Developer Portal verify that the score was included in the World ID App +integrity signature. + ```typescript title="app/api/verify-proof/route.ts" import { NextResponse } from "next/server"; import type { IDKitResult } from "@worldcoin/idkit"; diff --git a/world-id/idkit/javascript.mdx b/world-id/idkit/javascript.mdx index 83ef949..6f87416 100644 --- a/world-id/idkit/javascript.mdx +++ b/world-id/idkit/javascript.mdx @@ -28,7 +28,8 @@ yarn add @worldcoin/idkit-core - `IDKit.request(config)` for uniqueness proofs - `IDKit.requestWithInviteCode(config)` for invite-code mode -- `orbLegacy`, `secureDocumentLegacy`, `documentLegacy`, `selfieCheckLegacy` for presets +- `proofOfHuman`, `passport`, `selfieCheck`, and `identityCheck` for current presets +- `orbLegacy`, `secureDocumentLegacy`, `documentLegacy`, `selfieCheckLegacy`, and `deviceLegacy` for legacy presets Each entry point returns a builder. Finalize it with `.preset(...)`. @@ -81,6 +82,10 @@ After `.preset(...)`, you get an `IDKitRequest` object: - `pollUntilCompletion({ pollInterval, timeout })` - `getDebugReport()` +When you use `selfieCheck`, the successful result contains a +`SelfieCheckResponseItemV4`. Its required `sybil_score` field is a JavaScript +`number`. Forward the complete result to your backend before using the score. + ```ts import { IDKitErrorCodes } from "@worldcoin/idkit-core"; @@ -129,14 +134,14 @@ if (!completion.success) { Use `IDKit.requestWithInviteCode(config)` to open a landing page that displays both an invite code and a QR code. Validation, the returned `Status` shape, and the poll loop are identical to `IDKit.request`. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it. ```ts -import { IDKit, selfieCheckLegacy } from "@worldcoin/idkit-core"; +import { IDKit, selfieCheck } from "@worldcoin/idkit-core"; const request = await IDKit.requestWithInviteCode({ app_id: "app_xxxxx", action: "my-action", rp_context, - allow_legacy_proofs: true, -}).preset(selfieCheckLegacy({ signal: "user-123" })); + allow_legacy_proofs: false, +}).preset(selfieCheck({ signal: "user-123" })); const connectorURI = request.connectorURI; // URL with &c=&a= const expiresAt = request.expiresAt; // Unix seconds @@ -173,15 +178,18 @@ const request = await IDKit.requestWithInviteCode({ app_id: "app_xxxxx", action: "my-action", rp_context, - allow_legacy_proofs: true, -}).preset(selfieCheckLegacy({ signal: "user-123" })); + allow_legacy_proofs: false, +}).preset(selfieCheck({ signal: "user-123" })); const connectorURI = request.connectorURI; // display to user (URL with code embedded) const expiresAt = request.expiresAt; // drive a countdown const completion = await request.pollUntilCompletion(); ``` -The config object is unchanged. The `connectorURI` now includes `&c=&a=` params; use it alongside `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same. +The `connectorURI` now includes `&c=&a=` params; use it alongside +`expiresAt` in your UI. Polling, proof verification, and nullifier storage stay +the same. Set `allow_legacy_proofs` for the preset you choose; `selfieCheck` +always uses `false`. ## Server-side helpers diff --git a/world-id/idkit/kotlin.mdx b/world-id/idkit/kotlin.mdx index b0f8fae..fd0b008 100644 --- a/world-id/idkit/kotlin.mdx +++ b/world-id/idkit/kotlin.mdx @@ -71,6 +71,10 @@ if (completion is IDKitCompletionResult.Success) { } ``` +For `selfieCheck`, the successful result contains a `ResponseItem.SelfieV4` +item with a required `sybilScore: ULong` value. Forward the complete result to +your backend before using the score. + ## Presets ```kotlin @@ -80,6 +84,28 @@ import com.worldcoin.idkit.orbLegacy val request = IDKit.request(config).preset(orbLegacy(signal = "user-123")) ``` +Use `selfieCheck` for the World ID 4.0 Selfie Check credential. Set +`allowLegacyProofs` to `false`; the preset also enforces this value so it never +falls back to a legacy proof. + +```kotlin +import com.worldcoin.idkit.IDKit +import com.worldcoin.idkit.selfieCheck + +val selfieConfig = IDKitRequestConfig( + appId = "app_xxxxx", + action = "my-action", + rpContext = rpContext, + allowLegacyProofs = false, + returnTo = "myapp://verify-done", + environment = Environment.PRODUCTION, +) + +val request = IDKit.request(selfieConfig).preset( + selfieCheck(signal = "user-123") +) +``` + ## Polling patterns - `pollStatusOnce()` for manual loops diff --git a/world-id/idkit/mini-apps.mdx b/world-id/idkit/mini-apps.mdx index 9420b03..dce4810 100644 --- a/world-id/idkit/mini-apps.mdx +++ b/world-id/idkit/mini-apps.mdx @@ -37,7 +37,7 @@ The Mini-App-specific details: | Goal | IDKit preset | | --- | --- | | Strong sybil resistance or one-human-one-action checks | `proofOfHuman` | -| Lower-friction liveness or bot deterrence | `selfieCheckLegacy` | +| Lower-friction liveness or bot deterrence | `selfieCheck` | | Passport-backed checks | `passport` | Check out this [page](/world-id/idkit/credentials) to learn about the different World ID credentials and which preset to use for each. diff --git a/world-id/idkit/react.mdx b/world-id/idkit/react.mdx index ff2c1f3..1d94654 100644 --- a/world-id/idkit/react.mdx +++ b/world-id/idkit/react.mdx @@ -80,6 +80,11 @@ const rpContext: RpContext = { - If `handleVerify` throws/rejects, the widget enters an error state, emits `onError("failed_by_host_app")`, and does not call `onSuccess`. This means World App already returned a proof, but your callback or backend did not accept it. - `onError` is optional. +For `selfieCheck`, `result.responses` contains a typed +`SelfieCheckResponseItemV4` with a required numeric `sybil_score`. Only use the +score after `handleVerify` has successfully verified the complete result through +your backend. + ## Headless hooks ### `useIDKitRequest` @@ -122,7 +127,7 @@ Hook result fields: For invite-code flows, use `IDKitInviteCodeRequestWidget` (controlled) or `useIDKitInviteCodeRequest` (headless). Config matches `IDKitRequestWidget` / `useIDKitRequest` — invite-code mode adds no new required fields. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it. ```tsx -import { IDKitInviteCodeRequestWidget, selfieCheckLegacy } from "@worldcoin/idkit"; +import { IDKitInviteCodeRequestWidget, selfieCheck } from "@worldcoin/idkit"; { /* ... */ }} onSuccess={() => { /* ... */ }} />; @@ -172,7 +177,7 @@ import { IDKitRequestWidget, orbLegacy } from "@worldcoin/idkit"; ```tsx // After — invite-code widget -import { IDKitInviteCodeRequestWidget, selfieCheckLegacy } from "@worldcoin/idkit"; +import { IDKitInviteCodeRequestWidget, selfieCheck } from "@worldcoin/idkit"; ; diff --git a/world-id/idkit/swift.mdx b/world-id/idkit/swift.mdx index 95585b5..7f43ee0 100644 --- a/world-id/idkit/swift.mdx +++ b/world-id/idkit/swift.mdx @@ -76,13 +76,26 @@ case .failure(let error): } ``` +For `selfieCheck`, the successful result contains a `ResponseItem.selfieV4` +case with a required `sybilScore: UInt64` value. Forward the complete result to +your backend before using the score. + ## Invite-code mode Use `presetWithInviteCode(_:)` on the builder to return an `IDKitInviteCodeRequest` instead of `IDKitRequest`. The polling surface is identical. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it. ```swift -let request = try IDKit.request(config: config) - .presetWithInviteCode(selfieCheckLegacy(signal: "user-123")) +let selfieConfig = IDKitRequestConfig( + appId: "app_xxxxx", + action: "my-action", + rpContext: rpContext, + allowLegacyProofs: false, + returnTo: "myapp://verify-done", + environment: .production +) + +let request = try IDKit.request(config: selfieConfig) + .presetWithInviteCode(selfieCheck(signal: "user-123")) let connectorURL = request.connectorURL // URL with &c=&a= let expiresAt = request.expiresAt // Date @@ -102,15 +115,18 @@ let completion = await request.pollUntilCompletion() ```swift // After — invite-code mode -let request = try IDKit.request(config: config) - .presetWithInviteCode(selfieCheckLegacy(signal: "user-123")) +let request = try IDKit.request(config: selfieConfig) + .presetWithInviteCode(selfieCheck(signal: "user-123")) let connectorURL = request.connectorURL // display to user (URL with code embedded) let expiresAt = request.expiresAt // drive a countdown let completion = await request.pollUntilCompletion() ``` -The config object is unchanged. The `connectorURL` now includes `&c=&a=` params; use it alongside `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same. +The `connectorURL` now includes `&c=&a=` params; use it alongside +`expiresAt` in your UI. Polling, proof verification, and nullifier storage stay +the same. Set `allowLegacyProofs` for the preset you choose; `selfieCheck` +always uses `false`. `IDKitInviteCodeRequest` exposes: diff --git a/world-id/idkit/verification-flows.mdx b/world-id/idkit/verification-flows.mdx index a1467b6..597c063 100644 --- a/world-id/idkit/verification-flows.mdx +++ b/world-id/idkit/verification-flows.mdx @@ -130,4 +130,4 @@ sequenceDiagram **Integrate** -Setup is identical to the [standard integration](/world-id/idkit/integrate) — only the request call changes. Only the `selfieCheckLegacy` preset is supported for Selfie Check (Beta) today. It returns World ID 3.0 proofs; Selfie Check with World ID 4.0 is not available yet. For code samples and migration guides, see the per-SDK sections: [JavaScript](/world-id/idkit/javascript#invite-code-mode), [React](/world-id/idkit/react#invite-code-mode), [Swift](/world-id/idkit/swift#invite-code-mode). +Setup is identical to the [standard integration](/world-id/idkit/integrate) — only the request call changes. Use the `selfieCheck` preset with `allow_legacy_proofs: false` to request Selfie Check through invite-code mode. For code samples and migration guides, see the per-SDK sections: [JavaScript](/world-id/idkit/javascript#invite-code-mode), [React](/world-id/idkit/react#invite-code-mode), [Swift](/world-id/idkit/swift#invite-code-mode). diff --git a/world-id/overview.mdx b/world-id/overview.mdx index 43c46e2..4d716ae 100644 --- a/world-id/overview.mdx +++ b/world-id/overview.mdx @@ -54,7 +54,7 @@ Through credentials like Proof of Human, Document, and Selfie Check, World ID ex Selfie Check credential card -

Selfie Check Beta

+

Selfie Check

Low-friction liveness and uniqueness signal from a selfie flow. Best for sign-up and bot defense where speed matters most.

diff --git a/world-id/sandbox/testing-selfie-check.mdx b/world-id/sandbox/testing-selfie-check.mdx index 8c45d71..c35ef71 100644 --- a/world-id/sandbox/testing-selfie-check.mdx +++ b/world-id/sandbox/testing-selfie-check.mdx @@ -1,21 +1,16 @@ --- -title: "Testing Selfie Check (Beta) in Sandbox" -description: "Coverage, critical user journeys, and known limitations for testing your Selfie Check (Beta) integration in Sandbox." +title: "Testing Selfie Check in Sandbox" +description: "Coverage, critical user journeys, and known limitations for testing your Selfie Check integration in Sandbox." "og:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png" "twitter:image": "https://raw.githubusercontent.com/worldcoin/developer-docs/main/images/docs/docs-meta.png" --- {/* cspell:ignore idkit DoB reinstalls */} -Sandbox lets you run the full [Selfie Check (Beta)](/world-id/credentials/11) relying-party +Sandbox lets you run the full [Selfie Check](/world-id/credentials/11) relying-party journey end-to-end — from your surface, through IDKit, into the sandbox World ID app, and back — without touching production identities or real proofs. - - Selfie Check (Beta) must be enabled for your app before you can test it. To - enable the feature flag, request access through your World point of contact. - - New to Sandbox? Start with [What is Sandbox?](/world-id/sandbox/what-is-sandbox) and [How to get access](/world-id/sandbox/sandbox-access) before working through this guide. From ab9b001072aaadb8741134c4b015f0b0ef02b987 Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 2 Sep 2026 12:13:32 -0700 Subject: [PATCH 2/4] docs: clarify user presence response --- openapi/developer-portal.json | 6 +++--- snippets/idkit-response.mdx | 12 ++++-------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/openapi/developer-portal.json b/openapi/developer-portal.json index 3c5bc93..0d03b0b 100644 --- a/openapi/developer-portal.json +++ b/openapi/developer-portal.json @@ -1368,7 +1368,7 @@ }, "user_presence_completed": { "type": "boolean", - "description": "Whether World App completed the requested user-presence check. IDKit always sends it; treat a missing value as false." + "description": "Whether World App completed the requested user-presence check. IDKit includes this field only when `require_user_presence` was true in the request." } } }, @@ -1413,7 +1413,7 @@ }, "user_presence_completed": { "type": "boolean", - "description": "Whether World App completed the requested user-presence check. IDKit always sends it; treat a missing value as false." + "description": "Whether World App completed the requested user-presence check. IDKit includes this field only when `require_user_presence` was true in the request." } } }, @@ -1457,7 +1457,7 @@ }, "user_presence_completed": { "type": "boolean", - "description": "Whether World App completed the requested user-presence check. IDKit always sends it; treat a missing value as false." + "description": "Whether World App completed the requested user-presence check. IDKit includes this field only when `require_user_presence` was true in the request." } } }, diff --git a/snippets/idkit-response.mdx b/snippets/idkit-response.mdx index 578e658..d160817 100644 --- a/snippets/idkit-response.mdx +++ b/snippets/idkit-response.mdx @@ -13,8 +13,7 @@ "merkle_root": "0x0abc123...root_hash", "nullifier": "0x04e5f6...nullifier_hash" } - ], - "user_presence_completed": false + ] } ``` @@ -33,8 +32,7 @@ "issuer_schema_id": 1, "expires_at_min": 1756166400 } - ], - "user_presence_completed": false + ] } ``` @@ -61,8 +59,7 @@ "expires_at_min": 1788302888, "sybil_score": 10 } - ], - "user_presence_completed": true + ] } ``` @@ -81,8 +78,7 @@ "issuer_schema_id": 1, "expires_at_min": 1756166400 } - ], - "user_presence_completed": false + ] } ``` From f140b8633601f7a814e7bbd38595a342af3b6723 Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:34:28 -0700 Subject: [PATCH 3/4] bop --- openapi/developer-portal.json | 8 +++--- snippets/idkit-response.mdx | 2 +- world-id/SKILL.md | 2 +- world-id/credentials/11.mdx | 24 ++++-------------- world-id/idkit/credentials.mdx | 46 ++++------------------------------ world-id/idkit/kotlin.mdx | 2 +- 6 files changed, 17 insertions(+), 67 deletions(-) diff --git a/openapi/developer-portal.json b/openapi/developer-portal.json index 0d03b0b..738f095 100644 --- a/openapi/developer-portal.json +++ b/openapi/developer-portal.json @@ -743,7 +743,7 @@ } }, "selfie_check_v4": { - "summary": "Selfie Check (protocol 4.0)", + "summary": "Selfie Check", "value": { "protocol_version": "4.0", "nonce": "0xabc123", @@ -1279,7 +1279,7 @@ "IntegrityBundle": { "type": "object", "required": ["version", "signature_format", "timestamp", "signature", "jwt"], - "description": "World ID App integrity attestation. Selfie Check 4.0 requires version 2, which covers the disclosed `sybil_score`.", + "description": "World ID App integrity attestation. Selfie Check responses with `issuer_schema_id: 11` require version 2, which covers the disclosed `sybil_score`.", "properties": { "version": { "type": "integer", @@ -1527,7 +1527,7 @@ "sybil_score": { "type": "integer", "minimum": 0, - "description": "Selfie Check z-score decoded to an integer. Required only when `issuer_schema_id` is 11. Higher values indicate a stronger potential duplicate signal; this is not a probability or match count." + "description": "Versioned Selfie Check risk signal represented as an integer. Required only when `issuer_schema_id` is 11." } } }, @@ -1574,7 +1574,7 @@ "sybil_score": { "type": "integer", "minimum": 0, - "description": "Selfie Check z-score decoded to an integer. Required only when `issuer_schema_id` is 11." + "description": "Versioned Selfie Check risk signal represented as an integer. Required only when `issuer_schema_id` is 11." } } }, diff --git a/snippets/idkit-response.mdx b/snippets/idkit-response.mdx index d160817..1fc4feb 100644 --- a/snippets/idkit-response.mdx +++ b/snippets/idkit-response.mdx @@ -36,7 +36,7 @@ } ``` -```json title="World ID 4.0 Selfie Check" +```json title="Selfie Check" { "protocol_version": "4.0", "nonce": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", diff --git a/world-id/SKILL.md b/world-id/SKILL.md index 44bb06d..20a3d0e 100644 --- a/world-id/SKILL.md +++ b/world-id/SKILL.md @@ -107,7 +107,7 @@ Other legacy presets exist (`documentLegacy`, `selfieCheckLegacy`, `deviceLegacy ### Selfie Check -Use `selfieCheck`, which requests the World ID 4.0 Selfie Check credential and +Use `selfieCheck`, which requests the Selfie Check credential and always disables legacy proof fallback. Each Selfie Check response includes a required integer `sybil_score`; forward the complete IDKit result unchanged so the Developer Portal can verify the proof and version 2 integrity signature diff --git a/world-id/credentials/11.mdx b/world-id/credentials/11.mdx index 60f53f3..a46863b 100644 --- a/world-id/credentials/11.mdx +++ b/world-id/credentials/11.mdx @@ -43,25 +43,11 @@ other prerequisite credential is required. ## Understand the Sybil score -Each World ID 4.0 Selfie Check response includes `sybil_score`, a non-negative -integer derived from the z-score of the closest face-match signal. A higher value -means the match is more statistically unusual and is a stronger signal that the -person may already be enrolled. The score is not a probability, percentage, or -count of matching accounts. - -Treat `sybil_score` as one input to your abuse policy and choose a threshold that -fits your use case. Only use the score after your backend has forwarded the -complete IDKit result to the [Developer Portal verification endpoint](/api-reference/developer-portal/verify) -and received a successful response. The verifier requires integrity bundle version -2 for Selfie Check and verifies that the score is covered by the World ID App -integrity signature. - - - World ID 4.0 uniqueness proofs are one-time per action for each user. If the same - user needs to complete Selfie Check more than once, use a different action for - each check. Reusing the same action produces the same action-scoped nullifier and - cannot be accepted as a new one-time verification. - +Each Selfie Check response includes a versioned `sybil_score` that +can help an app assess the risk of repeated enrollment. It is a risk signal, not +a uniqueness verdict, and should be considered alongside other evidence. The +response also includes an `integrity_bundle` that lets the Developer Portal +verify it came from an authentic World ID App. ## How it works diff --git a/world-id/idkit/credentials.mdx b/world-id/idkit/credentials.mdx index ac6f9ff..13f1722 100644 --- a/world-id/idkit/credentials.mdx +++ b/world-id/idkit/credentials.mdx @@ -105,7 +105,7 @@ const preset = passport({ signal: "user-123" }); ## Selfie Check -Use `selfieCheck()` to request the World ID 4.0 Selfie Check credential. This +Use `selfieCheck()` to request Selfie Check. This preset always disables fallback to legacy proofs. Anyone with World ID App can complete the flow—no Orb or document credential is @@ -145,46 +145,10 @@ const preset = selfieCheck({ signal: "user-123" }); ``` -A successful Selfie Check response includes a required `sybil_score` on the -response item with `identifier: "selfie"` and `issuer_schema_id: 11`: - -```json -{ - "protocol_version": "4.0", - "action": "my-action", - "integrity_bundle": { - "version": 2, - "signature_format": "apple_app_attest", - "timestamp": 1788302923, - "signature": "...", - "jwt": "..." - }, - "responses": [ - { - "identifier": "selfie", - "issuer_schema_id": 11, - "nullifier": "0x...", - "proof": ["0x...", "0x...", "0x...", "0x...", "0x..."], - "expires_at_min": 1788302888, - "sybil_score": 10 - } - ] -} -``` - -The integer is derived from the disclosed face-match z-score. Higher values are -a stronger potential duplicate signal; the value is not a probability or a count -of matching accounts. Forward the complete response unchanged and only use -`sybil_score` after the Developer Portal verifies the proof and version 2 integrity -signature. See [Selfie Check](/world-id/credentials/11#understand-the-sybil-score) -for interpretation guidance. - - - If the same user needs to complete Selfie Check more than once, use a different - action for each World ID 4.0 uniqueness proof. Reusing the same action produces - the same action-scoped nullifier and cannot be accepted as a new one-time - verification. - +The response includes a required `sybil_score` and an `integrity_bundle` that +lets the Developer Portal verify the response came from an authentic World ID +App. Forward the complete IDKit result unchanged and only use the score after +server-side verification succeeds. To test your integration end-to-end, see [Testing Selfie Check in Sandbox](/world-id/sandbox/testing-selfie-check). diff --git a/world-id/idkit/kotlin.mdx b/world-id/idkit/kotlin.mdx index fd0b008..9aec6b8 100644 --- a/world-id/idkit/kotlin.mdx +++ b/world-id/idkit/kotlin.mdx @@ -84,7 +84,7 @@ import com.worldcoin.idkit.orbLegacy val request = IDKit.request(config).preset(orbLegacy(signal = "user-123")) ``` -Use `selfieCheck` for the World ID 4.0 Selfie Check credential. Set +Use `selfieCheck` for Selfie Check. Set `allowLegacyProofs` to `false`; the preset also enforces this value so it never falls back to a legacy proof. From dc0f5c4f8abbcc156e4d1cbb981d5877e7bfc795 Mon Sep 17 00:00:00 2001 From: Takis Kakalis <80459599+Takaros999@users.noreply.github.com> Date: Wed, 2 Sep 2026 14:47:39 -0700 Subject: [PATCH 4/4] beep --- world-id/SKILL.md | 15 +++++++-------- world-id/idkit/credentials.mdx | 9 +++------ world-id/idkit/integrate.mdx | 5 ----- world-id/idkit/javascript.mdx | 21 +++++++-------------- world-id/idkit/kotlin.mdx | 26 -------------------------- world-id/idkit/react.mdx | 17 ++++++----------- world-id/idkit/swift.mdx | 26 +++++--------------------- world-id/idkit/verification-flows.mdx | 2 +- 8 files changed, 29 insertions(+), 92 deletions(-) diff --git a/world-id/SKILL.md b/world-id/SKILL.md index 20a3d0e..966f3ff 100644 --- a/world-id/SKILL.md +++ b/world-id/SKILL.md @@ -103,20 +103,19 @@ The credential decides what the user proves. Nail this down before scaffolding **DO NOT default to `proofOfHuman` if the user said "passport" or "verify their ID"** — that's `passport`. **DO NOT default to `proofOfHuman` if the user said "selfie" or "liveness"** — that's `selfieCheck`. When in doubt, ask one question. -Other legacy presets exist (`documentLegacy`, `selfieCheckLegacy`, `deviceLegacy`); reach for them only when the user asks specifically. For sign-in / session reuse across visits, use the v4 **session** flow instead of a uniqueness preset (see the integrate doc). +Other legacy presets exist (`documentLegacy`, `deviceLegacy`); reach for them only when the user asks specifically. For sign-in / session reuse across visits, use the v4 **session** flow instead of a uniqueness preset (see the integrate doc). ### Selfie Check -Use `selfieCheck`, which requests the Selfie Check credential and -always disables legacy proof fallback. Each Selfie Check response includes a -required integer `sybil_score`; forward the complete IDKit result unchanged so -the Developer Portal can verify the proof and version 2 integrity signature -before the app uses the score. +Use `selfieCheck`, which requests the Selfie Check credential. Each Selfie Check +response includes a required integer `sybil_score`; forward the complete IDKit +result unchanged so the Developer Portal can verify the proof and version 2 +integrity signature before the app uses the score. World ID 4.0 uniqueness proofs are one-time per action for each user. If the same user needs to complete Selfie Check more than once, use a different action -for each check. Keep the deprecated `selfieCheckLegacy` preset only when -maintaining an existing World ID 3.0 integration. +for each check. Migrate existing `selfieCheckLegacy` integrations to +`selfieCheck`. ## Phase 4 — Implement the 6 integration steps and explain the WHY diff --git a/world-id/idkit/credentials.mdx b/world-id/idkit/credentials.mdx index 13f1722..4cb841e 100644 --- a/world-id/idkit/credentials.mdx +++ b/world-id/idkit/credentials.mdx @@ -105,8 +105,7 @@ const preset = passport({ signal: "user-123" }); ## Selfie Check -Use `selfieCheck()` to request Selfie Check. This -preset always disables fallback to legacy proofs. +Use `selfieCheck()` to request Selfie Check. Anyone with World ID App can complete the flow—no Orb or document credential is required. Forward the complete IDKit result to the @@ -150,6 +149,8 @@ lets the Developer Portal verify the response came from an authentic World ID App. Forward the complete IDKit result unchanged and only use the score after server-side verification succeeds. +If you use the legacy `selfieCheckLegacy` preset, migrate to `selfieCheck`. + To test your integration end-to-end, see [Testing Selfie Check in Sandbox](/world-id/sandbox/testing-selfie-check). ## Identity Check (Preview) @@ -280,10 +281,6 @@ These presets only return World ID 3.0 proofs. Use them for existing integration documentLegacy At least a Document verification. Returns the user's highest legacy credential: Document, Secure Document, or Orb. - - selfieCheckLegacy - Deprecated. Returns the World ID 3.0 Selfie Check proof. Keep it only for an existing legacy integration; use selfieCheck for new integrations. - deviceLegacy Deprecated. Keep deviceLegacy only for existing Device integrations. For new integrations, use Selfie Check. diff --git a/world-id/idkit/integrate.mdx b/world-id/idkit/integrate.mdx index 2ede2bc..abbef5b 100644 --- a/world-id/idkit/integrate.mdx +++ b/world-id/idkit/integrate.mdx @@ -313,11 +313,6 @@ forward it directly to `POST https://developer.world.org/api/v4/verify/{rp_id}`. Forward the IDKit result payload as-is. No field remapping is required. -For Selfie Check, only use `responses[].sybil_score` after this endpoint returns -success. Selfie Check responses require integrity bundle version 2, which lets -the Developer Portal verify that the score was included in the World ID App -integrity signature. - ```typescript title="app/api/verify-proof/route.ts" import { NextResponse } from "next/server"; import type { IDKitResult } from "@worldcoin/idkit"; diff --git a/world-id/idkit/javascript.mdx b/world-id/idkit/javascript.mdx index 6f87416..03d8ce6 100644 --- a/world-id/idkit/javascript.mdx +++ b/world-id/idkit/javascript.mdx @@ -29,7 +29,7 @@ yarn add @worldcoin/idkit-core - `IDKit.request(config)` for uniqueness proofs - `IDKit.requestWithInviteCode(config)` for invite-code mode - `proofOfHuman`, `passport`, `selfieCheck`, and `identityCheck` for current presets -- `orbLegacy`, `secureDocumentLegacy`, `documentLegacy`, `selfieCheckLegacy`, and `deviceLegacy` for legacy presets +- `orbLegacy`, `secureDocumentLegacy`, `documentLegacy`, and `deviceLegacy` for legacy presets Each entry point returns a builder. Finalize it with `.preset(...)`. @@ -82,10 +82,6 @@ After `.preset(...)`, you get an `IDKitRequest` object: - `pollUntilCompletion({ pollInterval, timeout })` - `getDebugReport()` -When you use `selfieCheck`, the successful result contains a -`SelfieCheckResponseItemV4`. Its required `sybil_score` field is a JavaScript -`number`. Forward the complete result to your backend before using the score. - ```ts import { IDKitErrorCodes } from "@worldcoin/idkit-core"; @@ -134,14 +130,14 @@ if (!completion.success) { Use `IDKit.requestWithInviteCode(config)` to open a landing page that displays both an invite code and a QR code. Validation, the returned `Status` shape, and the poll loop are identical to `IDKit.request`. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it. ```ts -import { IDKit, selfieCheck } from "@worldcoin/idkit-core"; +import { IDKit, proofOfHuman } from "@worldcoin/idkit-core"; const request = await IDKit.requestWithInviteCode({ app_id: "app_xxxxx", action: "my-action", rp_context, - allow_legacy_proofs: false, -}).preset(selfieCheck({ signal: "user-123" })); + allow_legacy_proofs: true, +}).preset(proofOfHuman({ signal: "user-123" })); const connectorURI = request.connectorURI; // URL with &c=&a= const expiresAt = request.expiresAt; // Unix seconds @@ -178,18 +174,15 @@ const request = await IDKit.requestWithInviteCode({ app_id: "app_xxxxx", action: "my-action", rp_context, - allow_legacy_proofs: false, -}).preset(selfieCheck({ signal: "user-123" })); + allow_legacy_proofs: true, +}).preset(proofOfHuman({ signal: "user-123" })); const connectorURI = request.connectorURI; // display to user (URL with code embedded) const expiresAt = request.expiresAt; // drive a countdown const completion = await request.pollUntilCompletion(); ``` -The `connectorURI` now includes `&c=&a=` params; use it alongside -`expiresAt` in your UI. Polling, proof verification, and nullifier storage stay -the same. Set `allow_legacy_proofs` for the preset you choose; `selfieCheck` -always uses `false`. +The config object is unchanged. The `connectorURI` now includes `&c=&a=` params; use it alongside `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same. ## Server-side helpers diff --git a/world-id/idkit/kotlin.mdx b/world-id/idkit/kotlin.mdx index 9aec6b8..b0f8fae 100644 --- a/world-id/idkit/kotlin.mdx +++ b/world-id/idkit/kotlin.mdx @@ -71,10 +71,6 @@ if (completion is IDKitCompletionResult.Success) { } ``` -For `selfieCheck`, the successful result contains a `ResponseItem.SelfieV4` -item with a required `sybilScore: ULong` value. Forward the complete result to -your backend before using the score. - ## Presets ```kotlin @@ -84,28 +80,6 @@ import com.worldcoin.idkit.orbLegacy val request = IDKit.request(config).preset(orbLegacy(signal = "user-123")) ``` -Use `selfieCheck` for Selfie Check. Set -`allowLegacyProofs` to `false`; the preset also enforces this value so it never -falls back to a legacy proof. - -```kotlin -import com.worldcoin.idkit.IDKit -import com.worldcoin.idkit.selfieCheck - -val selfieConfig = IDKitRequestConfig( - appId = "app_xxxxx", - action = "my-action", - rpContext = rpContext, - allowLegacyProofs = false, - returnTo = "myapp://verify-done", - environment = Environment.PRODUCTION, -) - -val request = IDKit.request(selfieConfig).preset( - selfieCheck(signal = "user-123") -) -``` - ## Polling patterns - `pollStatusOnce()` for manual loops diff --git a/world-id/idkit/react.mdx b/world-id/idkit/react.mdx index 1d94654..331a54b 100644 --- a/world-id/idkit/react.mdx +++ b/world-id/idkit/react.mdx @@ -80,11 +80,6 @@ const rpContext: RpContext = { - If `handleVerify` throws/rejects, the widget enters an error state, emits `onError("failed_by_host_app")`, and does not call `onSuccess`. This means World App already returned a proof, but your callback or backend did not accept it. - `onError` is optional. -For `selfieCheck`, `result.responses` contains a typed -`SelfieCheckResponseItemV4` with a required numeric `sybil_score`. Only use the -score after `handleVerify` has successfully verified the complete result through -your backend. - ## Headless hooks ### `useIDKitRequest` @@ -127,7 +122,7 @@ Hook result fields: For invite-code flows, use `IDKitInviteCodeRequestWidget` (controlled) or `useIDKitInviteCodeRequest` (headless). Config matches `IDKitRequestWidget` / `useIDKitRequest` — invite-code mode adds no new required fields. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it. ```tsx -import { IDKitInviteCodeRequestWidget, selfieCheck } from "@worldcoin/idkit"; +import { IDKitInviteCodeRequestWidget, proofOfHuman } from "@worldcoin/idkit"; { /* ... */ }} onSuccess={() => { /* ... */ }} />; @@ -177,7 +172,7 @@ import { IDKitRequestWidget, orbLegacy } from "@worldcoin/idkit"; ```tsx // After — invite-code widget -import { IDKitInviteCodeRequestWidget, selfieCheck } from "@worldcoin/idkit"; +import { IDKitInviteCodeRequestWidget, proofOfHuman } from "@worldcoin/idkit"; ; diff --git a/world-id/idkit/swift.mdx b/world-id/idkit/swift.mdx index 7f43ee0..9bc1362 100644 --- a/world-id/idkit/swift.mdx +++ b/world-id/idkit/swift.mdx @@ -76,26 +76,13 @@ case .failure(let error): } ``` -For `selfieCheck`, the successful result contains a `ResponseItem.selfieV4` -case with a required `sybilScore: UInt64` value. Forward the complete result to -your backend before using the score. - ## Invite-code mode Use `presetWithInviteCode(_:)` on the builder to return an `IDKitInviteCodeRequest` instead of `IDKitRequest`. The polling surface is identical. See [Invite-code mode](/world-id/idkit/verification-flows#with-invite-code-mode) for when to use it. ```swift -let selfieConfig = IDKitRequestConfig( - appId: "app_xxxxx", - action: "my-action", - rpContext: rpContext, - allowLegacyProofs: false, - returnTo: "myapp://verify-done", - environment: .production -) - -let request = try IDKit.request(config: selfieConfig) - .presetWithInviteCode(selfieCheck(signal: "user-123")) +let request = try IDKit.request(config: config) + .presetWithInviteCode(proofOfHuman(signal: "user-123")) let connectorURL = request.connectorURL // URL with &c=&a= let expiresAt = request.expiresAt // Date @@ -115,18 +102,15 @@ let completion = await request.pollUntilCompletion() ```swift // After — invite-code mode -let request = try IDKit.request(config: selfieConfig) - .presetWithInviteCode(selfieCheck(signal: "user-123")) +let request = try IDKit.request(config: config) + .presetWithInviteCode(proofOfHuman(signal: "user-123")) let connectorURL = request.connectorURL // display to user (URL with code embedded) let expiresAt = request.expiresAt // drive a countdown let completion = await request.pollUntilCompletion() ``` -The `connectorURL` now includes `&c=&a=` params; use it alongside -`expiresAt` in your UI. Polling, proof verification, and nullifier storage stay -the same. Set `allowLegacyProofs` for the preset you choose; `selfieCheck` -always uses `false`. +The config object is unchanged. The `connectorURL` now includes `&c=&a=` params; use it alongside `expiresAt` in your UI. Polling, proof verification, and nullifier storage stay the same. `IDKitInviteCodeRequest` exposes: diff --git a/world-id/idkit/verification-flows.mdx b/world-id/idkit/verification-flows.mdx index 597c063..8e20009 100644 --- a/world-id/idkit/verification-flows.mdx +++ b/world-id/idkit/verification-flows.mdx @@ -130,4 +130,4 @@ sequenceDiagram **Integrate** -Setup is identical to the [standard integration](/world-id/idkit/integrate) — only the request call changes. Use the `selfieCheck` preset with `allow_legacy_proofs: false` to request Selfie Check through invite-code mode. For code samples and migration guides, see the per-SDK sections: [JavaScript](/world-id/idkit/javascript#invite-code-mode), [React](/world-id/idkit/react#invite-code-mode), [Swift](/world-id/idkit/swift#invite-code-mode). +Setup is identical to the [standard integration](/world-id/idkit/integrate) — only the request call changes. Choose the appropriate preset in [Configure Credentials](/world-id/idkit/credentials). For code samples and migration guides, see the per-SDK sections: [JavaScript](/world-id/idkit/javascript#invite-code-mode), [React](/world-id/idkit/react#invite-code-mode), [Swift](/world-id/idkit/swift#invite-code-mode).