Incognito Actions
Cloud Incognito Actions
IDKit is required in your app's frontend for Incognito Actions, and the zero-knowledge proof received from the user will be verified via the Developer Portal API in your backend.
Creating actions
Create an action for your app in the Developer Portal. You must provide the following values:
- Action Name: The stringified action to be taken by the user.
- Description: This is shown to your user in the World app as they sign with their World ID. Make sure to fully describe the exact action the user is taking.
- Max Verifications: The number of times a user can take this action. A value of
0
indicates that unlimited verifications can take place.
An action scopes uniqueness for users, which means users will always generate the same ID (nullifier hash) when performing the same action. Cloud actions natively handle sybil-resistance with a limit set in the Developer Portal.
Installing IDKit
The JS package can be included in your project either as a module (which supports tree shaking to reduce bundle size) or you can add the script directly to your website.
Install IDKit
npm install @worldcoin/idkit
Usage
Import and render IDKit. You'll want to do this on the screen where the user executes the protected action (e.g. before they click "Claim airdrop" or "Vote on proposal").
import { IDKitWidget, VerificationLevel } from '@worldcoin/idkit'
<IDKitWidget
app_id="app_GBkZ1KlVUdFTjeMXKlVUdFT" // obtained from the Developer Portal
action="vote_1" // this is your action id from the Developer Portal
onSuccess={onSuccess} // callback when the modal is closed
handleVerify={handleVerify} // optional callback when the proof is received
verification_level={VerificationLevel.Device}
>
{({ open }) => <button onClick={open}>Verify with World ID</button>}
</IDKitWidget>
More configuration options can be found in the IDKit reference.
When a user clicks the button, the IDKit modal will open and prompt them to scan a QR code and verify with World ID. Once this proof is received, the optional handleVerify
callback is called immediately and the onSuccess
callback will be called when the modal is closed.
One of these callbacks should begin the process of verifying the proof.
Response
Upon successful completion of the World ID flow, you will receive a response object. This response object of type ISuccessResult
has the following attributes. Normally, you will forward these parameters to your backend for verification.
ISuccessResult
{
"merkle_root": "0x1f38b57f3bdf96f05ea62fa68814871bf0ca8ce4dbe073d8497d5a6b0a53e5e0",
"nullifier_hash": "0x0339861e70a9bdb6b01a88c7534a3332db915d3d06511b79a5724221a6958fbe",
"proof": "0x063942fd7ea1616f17787d2e3374c1826ebcd2d41d2394...",
"verification_level": "orb"
}
- Name
merkle_root
- Type
- string
- Description
This is the hash pointer to the root of the Merkle tree that proves membership of the user's identity in the list of identities verified by the Orb.
- Name
nullifier_hash
- Type
- string
- Description
The unique identifier for this combination of user, app, and action.
- Name
proof
- Type
- string
- Description
The Zero-knowledge proof of the verification.
- Name
verification_level
- Type
- "orb" | "device"
- Description
Either
orb
ordevice
. Returns the verification_level used to generate the proof.
Verifying Proofs
This section describes how to verify proofs via the Developer Portal API.
You should pass the proof to your backend when verifying proofs via the API. Users can manipulate information in the frontend, so the proof must be verified in a trusted environment.
Your backend should receive the ISuccessResult
object returned by IDKit, as well as the signal
that was input into IDKit, and send it to the Developer Portal API for verification using the verifyCloudProof
helper.
The action
ID should be accessible in your backend as an environment variable.
After performing your own backend actions based on the result, you then pass the success or error messages back to your frontend.
pages/api/verify.ts
import { type IVerifyResponse, verifyCloudProof } from '@worldcoin/idkit'
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { proof, signal } = req.body
const app_id = process.env.APP_ID
const action = process.env.ACTION_ID
const verifyRes = (await verifyCloudProof(proof, app_id, action, signal)) as IVerifyResponse
if (verifyRes.success) {
// This is where you should perform backend actions if the verification succeeds
// Such as, setting a user as "verified" in a database
res.status(200).send(verifyRes);
} else {
// This is where you should handle errors from the World ID /verify endpoint.
// Usually these errors are due to a user having already verified.
res.status(400).send(verifyRes);
}
};
Post-Verification
If handleVerify
does not throw an error, the user will see a success state and the onSuccess
callback will be called when the modal is closed. The onSuccess
callback should redirect a user to a success page, or perform any other actions you want to take after a user has been verified.
pages/index.tsx
const onSuccess = (result: ISuccessResult) => {
// This is where you should perform frontend actions once a user has been verified
window.alert(
`Successfully verified with World ID!
Your nullifier hash is: ` + result.nullifier_hash
)
}