Add World ID to your app
For developers: give this file to your coding agent with a one-line ask like “help me add World ID to my app.” The agent will figure out the rest.What is World ID? A privacy-preserving way to prove a user is a unique real human. Use it to gate signups, kill bots, prevent multi-accounting, run one-person-one-vote, or distribute scarce rewards fairly. Zero PII shared, zero-knowledge proofs on the wire. The full integration guide with code for every language lives at https://docs.world.org/world-id/idkit/integrate. This file is the meta-guide that gets you to the right code without missteps.
Agent: read these instructions before doing anything
Take the user from “I want World ID” to a verified working flow. Inspect first, ask only for missing information, and resume from the user’s actual state instead of restarting setup.Phase 0 — Establish readiness
Before changing code or creating Portal resources:- Read the project and inspect connected tools. Do not ask for information you can infer.
- Establish the current state:
- integration goal and credential preset
- new or existing project; client, backend, package manager, and persistence layer
- Developer Portal account/team,
app_id,rp_id, and action - 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
- credential access, especially Face Check
- 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.
- Build a TODO from the missing steps. Preserve working configuration and existing Portal resources unless the user explicitly wants replacements.
Phase 1 — Use the Developer Portal MCP when available
The World ID Developer Portal MCP turns the app-creation lifecycle into MCP tools. It replaces dashboard setup with a few tool calls and makes the one-timesigning_key response explicit so the agent can persist it immediately.
- Source & full tool reference: https://github.com/worldcoin/developer-portal/tree/main/web/api/mcp
- Endpoint:
https://developer.world.org/api/mcp(transport: streamable-http) - Auth:
Authorization: Bearer api_<base64(id:secret)>(Developer Portal team API key)
get_team_context, then use get_app_config for the selected app before creating anything. Clients may namespace MCP tools differently; match these final tool names:
If the MCP is not connected, explain that it can inspect and configure the user’s Portal resources directly. Offer the client-specific setup at https://docs.world.org/model-context-protocol/developer-portal, or let the user continue through the dashboard. Do not silently choose a path or block an otherwise valid integration on MCP setup.
Phase 2 — Understand the project before writing anything
Two paths land here. Identify which:- Path 1 — Building from scratch (demo, hackathon, new product). You have full control of the stack. Default to Next.js (App Router) + TypeScript as the golden path — it’s what every official sample uses and it’s the fastest way to a working flow.
- Path 2 — Integrating into an existing stack. Read the codebase first. Confirm the frontend (web / mobile) and the backend (where secrets live), then pick the right SDK pair from below.
DO NOT pin SDKs to
^2.x or ^3.x — those examples litter the public internet and will not work with v4. The API was redesigned. Pin ^4.x and verify with npm view @worldcoin/idkit version if uncertain.
Phase 3 — Pick the credential and confirm access
The credential decides what the user proves. Get this explicit before scaffolding — switching later means a new action.
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.
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).
Face Check access gate
After the app and action exist—but before implementing or opening a Face Check flow—confirm that theapp_id is enabled:
If either resource is missing, mark this gate pending, provision the resource in Phase 4 step 2, and return here before implementing the client request.
-
Prefer
get_app_configif the MCP response exposesenable_face_check. -
Otherwise call the public precheck endpoint with the real app and action:
-
Read
enable_face_checkfrom the response:true: continue.false: stop and tell the user that Face Check is not enabled for this app. Point them to their World contact or a documented support path to request access; if no request path is documented, say so instead of inventing one. Do not let the integration fail as an unexplained spinner.- missing field or failed precheck: treat access as unknown, surface the response details, and resolve the gate before continuing.
Phase 4 — Implement the 6 integration steps and explain the WHY
The full code for each step is at https://docs.world.org/world-id/idkit/integrate. Don’t reproduce it; link to it and adapt to the user’s framework. What the agent owns is making sure each step is done and understood. Copy this checklist into your TODO and update it as you go. Don’t move on with an unchecked step.- Step 1 — Install IDKit
- Step 2 — Create or reuse app + RP + action (store any newly generated signing key immediately)
- Step 3 — Sign RP request in backend
- Step 4 — Open IDKit widget on client
- Step 5 — Verify proof in backend
- Step 6 — Store nullifier with UNIQUE constraint
- Install IDKit —
^4.x, the right package for the platform (table in Phase 2). - Create or reuse the Portal resources. Use the MCP when available. Reuse an existing app, RP, and action when they match the requested integration. For a new RP, capture
app_id,rp_id, andsigning_key.private_keyfromconfigure_world_id, create the action in the intended environment, and write the signing key to the prepared server-only secret store in the same step. The portal returns it exactly once. Do not print, log, or return the private key to chat. If the key is lost, explain thatget_world_id_signing_keycannot recover it; rotation creates a new key and invalidates the old signer. - Generate the RP signature in your backend. Why backend? The signing key authenticates your app to the protocol. Leaking it lets anyone impersonate your app and forge proof requests. CRITICAL: never sign on the client. Never expose
RP_SIGNING_KEYas aNEXT_PUBLIC_*var. Never log it. - Open the IDKit widget on the client with the signature your backend returned. The widget hands off to World ID, which produces a zero-knowledge proof.
- Verify the proof in your backend by POSTing it as-is to
https://developer.world.org/api/v4/verify/{rp_id}. Why backend? A client can return any JSON it wants. Only the World verifier — called from a trusted server — confirms the proof is real and tied to a unique credential. Verifying client-side defeats the entire point. DO NOT mutate, re-encode, or trim the proof JSON before forwarding — pass exactly what IDKit returned. - Store the nullifier. Every successful proof returns a
nullifier— an RP-scoped, action-scoped, non-reversible identifier for that user. Why store it? Without uniqueness storage, a user can verify the same proof twice and double-claim a reward, vote, etc. Persist(action, nullifier)with aUNIQUEconstraint and reject duplicates on insert. Column type:NUMERIC(78, 0)(256-bit field elements). The nullifier reveals nothing about the user — it’s safe to store, but it’s the only anti-replay mechanism, so it’s required.
Phase 5 — Match environments end-to-end
- The production World ID app only signs production proofs.
- A staging action only verifies against the World ID Simulator (https://simulator.worldcoin.org).
- The IDKit
environmentprop, the action’senvironment, and the simulator-vs-real-app choice must all match.
production. A staging action with the production World ID app will silently produce zero proofs and look like a frontend bug. If the user needs both simulator testing and real-device QA, create separate staging and production actions.
Phase 6 — Test the integration end-to-end
Do not declare the integration complete from compilation or Portal configuration alone. Test the selected path and record evidence:- RP-signing endpoint succeeds without exposing or logging secrets.
- Widget/request opens in the selected environment.
- The selected credential completes with the staging simulator or production World ID as intended.
- 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 Face Check, invalid action/signature, or environment mismatch—produce an actionable user-facing error instead of an indefinite loading state.
- JS/React failures retain the
debugReportandrequest_idneeded for diagnosis without logging secrets.
Phase 7 — Gotchas and recovery
Surface these proactively when you see the corresponding symptom — don’t make the user search for the cause.Phase 8 — Hand off with evidence
Before declaring done, report:- the readiness state you found and which path you followed
- files and routes changed
app_id,rp_id, action, and environments configured—never secret values- commands and tests run, with results
- simulator, phone, or production checks still outstanding
- blockers and exact recovery steps
-
RP_SIGNING_KEYis server-only, in a real secret store, never logged. - Action exists in
production(not juststaging). - Nullifier persistence is real — DB-backed,
NUMERIC(78, 0),UNIQUE (action, nullifier). The in-memorySetyou may see in samples is illustrative only. - On-chain registration polled to
registered(get_world_id_registration_status) before launch. - The user knows that a leaked or lost signing key requires confirmed rotation and redeployment.
Reference
- Full integration guide (code for every language): https://docs.world.org/world-id/idkit/integrate
- Core concepts: https://docs.world.org/world-id/concepts
- Credentials reference: https://docs.world.org/world-id/credentials
- RP signature spec (for non-Node backends): https://docs.world.org/world-id/idkit/signatures
- Error codes: https://docs.world.org/world-id/idkit/error-codes
- Developer Portal MCP: https://github.com/worldcoin/developer-portal/tree/main/web/api/mcp
- Developer Portal: https://developer.world.org
- World ID Simulator (staging only): https://simulator.worldcoin.org