Further Reading

Protocol Internals

Documentation of certain protocol elements. Intended for internal use only.

The universal link is used so that the World App can recognize a World ID request and handle it correctly. As more clients are built, the universal link will be extended to other wallets. The structure of the universal link is documented here. The source of truth function for this can be found on GitHub, buildQRData function.

  • The universal link base is:
    • There is one required query string, w, which contains the WalletConnect URI
    • There is one optional query string, r, which contains a return URL for mobile app verifications

According to guidance from the WalletConnect team, only v2 URIs are supported.

External Nullifier

Within Semaphore, the zero knowledge protocol that World ID is based on, the external nullifier is a public 32-byte value that scopes the uniqueness of verifications. It is one of two inputs in the ZK circuit, the other being the secret identity nullifier. These two values are hashed to produce the nullifier hash, which identifies the user.

World ID actions (whether for Sign In or anonymous actions) are identified by their external nullifiers. This value is derived from the app_id and stringified action passed by IDKit to the World app. Our implementation can be found here.

Generally you won't need to generate the external nullifier yourself. IDKit will handle this automatically, but for custom integrations it's helpful to keep this in mind. When performing a request to the /precheck endpoint, you must pass the valid external nullifier for the given app_id and action. You can accomplish this with the generateExternalNullifier function from IDKit:

import { IDKitInternal } from '@worldcoin/idkit'

const getExternalNullifier = (app_id: string, action: string) => {
	return IDKitInternal.generateExternalNullifier(app_id, action).digest

getExternalNullifier('app_staging_7550e829082fc558e112e0620c1c7a59', 'test action')

OpenID Connect Claims

Within the ID token returned by the World ID provider, a minimal number of OIDC claims are set. This is due to the privacy-focused nature of the protocol. The set claims are:

  • iss: The issuer of the token, always ""
  • sub: The unique user identifier for the specific application (this is the nullifier_hash from the World ID ZKP)
  • aud: The identifier of the requesting application. This is always the app_id from the Developer Portal or /register endpoint
  • jti: A unique identifier for this ID token, only used once
  • iat: The timestamp of the token issuance
  • exp: The timestamp of the token's expiration
  • alg: The algorithm used to sign the ID token, only RS256 is supported
  • scope: The scopes requested by the application. Must always contain openid. The profile and email scopes are also supported for compatibility, but use should be avoided.
  • Describes claims specific to World ID. Subject to change
    • likely_human: "strong" or "weak", corresponding to whether the user has strong sybil protection or likelihood of being human. Biometrically verified users have a strong value.
    • credential_type: orb or phone, represents the credential the user to authenticate. In general, for Sign in with Worldcoin, the highest credential available to the user will be used.

Signup Sequencer

World ID utilizes a sequencer to insert identity commitments on-chain, generate inclusion proofs, and track the state of the contract Merkle trees. This is done to simplify the amount of state applications need to handle to work with World ID.

The sequencer utilizes a batching process to reduce gas costs and improve performance. When verifying a proof from the World app, the Developer Portal will query the sequencer to determine if the proof is valid, since the user could be a part of the current batch (which is not yet on-chain). To interact with the sequencer, you can use these endpoints:


  • Orb credential:
  • Phone credential:


  • Orb credential:
  • Phone credential:


The sequencer exposes the following endpoints:

  • /inclusionProof: Fetches the inclusion proof for a given identity commitment
  • /insertIdentity: Inserts an identity commitment into the current sequencer batch
  • /verifySemaphoreProof: Verifies the given ZK proof (from the World app) is valid, even if it is not yet on-chain

More details about these endpoints can be found in our Swagger documentation.