Self Protocol Integration
Self lets users prove identity attributes (age, nationality, humanity) from passports/ID cards using zero-knowledge proofs — no personal data exposed. Users scan their document's NFC chip in the Self mobile app and share a zk proof with your app.
Quick Start (Next.js Off-Chain)
1. Install
npm install @selfxyz/qrcode @selfxyz/core
2. Frontend — QR Code Component
"use client";
import { SelfQRcodeWrapper, SelfAppBuilder } from "@selfxyz/qrcode";
export default function VerifyIdentity({ userId }: { userId: string }) {
const selfApp = new SelfAppBuilder({
appName: "My App",
scope: "my-app-scope",
endpoint: "https://yourapp.com/api/verify",
endpointType: "https",
userId,
userIdType: "hex",
disclosures: {
minimumAge: 18,
},
}).build();
return (
<SelfQRcodeWrapper
selfApp={selfApp}
onSuccess={() => console.log("Verified")}
type="websocket"
darkMode={false}
/>
);
}
3. Backend — Verification Endpoint
// app/api/verify/route.ts
import { SelfBackendVerifier, DefaultConfigStore } from "@selfxyz/core";
export async function POST(req: Request) {
const { proof, publicSignals } = await req.json();
const verifier = new SelfBackendVerifier(
"my-app-scope", // must match frontend scope
"https://yourapp.com/api/verify", // must match frontend endpoint
true, // true = accept mock passports (dev only)
null, // allowedIds (null = all)
new DefaultConfigStore({ // must match frontend disclosures
minimumAge: 18,
})
);
const result = await verifier.verify(proof, publicSignals);
return Response.json({
verified: result.isValid,
nationality: result.credentialSubject?.nationality,
});
}
Integration Patterns
| Pattern | When to Use | endpoint | endpointType |
|---|---|---|---|
| Off-chain (backend) | Web apps, APIs, most cases | Your API URL | "https" or "https-staging" |
| On-chain (contract) | DeFi, token gating, airdrops | Contract address (lowercase) | "celo" or "celo-staging" |
| Deep linking | Mobile-first flows | Your API URL | "https" |
- Off-chain: Fastest to implement. Proof sent to your backend, verified server-side.
- On-chain: Proof verified by Celo smart contract. Inherit
SelfVerificationRoot. Use for trustless/permissionless scenarios. - Deep linking: For mobile users — opens Self app directly instead of QR scan. See
references/frontend.md.
Critical Gotchas
-
Config matching is mandatory — Frontend
disclosuresmust EXACTLY match backend/contract verification config. Mismatched age thresholds, country lists, or OFAC settings cause silent failures. -
Contract addresses must be lowercase — Non-checksum format in frontend
endpoint. Use.toLowerCase(). -
Country codes are ISO 3-letter — e.g.,
"USA","IRN","PRK". Max 40 countries in exclusion lists. -
Mock passports = testnet only — Set
mockPassport: truein backend / use"celo-staging"endpoint type. Real passports require mainnet. To create a mock passport: open Self app, tap the Passport button 5 times. Mock testing requires OFAC disabled. -
Version requirement —
@selfxyz/core>= 1.1.0-beta.1. -
Attestation IDs —
1= Passport,2= Biometric ID Card. Must explicitly allow viaallowedIdsmap. -
Scope uniqueness — On-chain, scope is Poseidon-hashed with contract address, preventing cross-contract proof replay.
-
Endpoint must be publicly accessible — Self app sends proof directly to your endpoint. Use ngrok for local development.
-
Common errors:
ScopeMismatch= scope/address mismatch or non-lowercase address.Invalid 'to' Address= wrongendpointType(celo vs https).InvalidIdentityCommitmentRoot= real passport on testnet (use mainnet).Invalid Config ID= mock passport on mainnet (use testnet).
Deployed Contracts (Celo)
| Network | Address |
|---|---|
| Mainnet Hub V2 | 0xe57F4773bd9c9d8b6Cd70431117d353298B9f5BF |
| Sepolia Hub V2 | 0x16ECBA51e18a4a7e61fdC417f0d47AFEeDfbed74 |
| Sepolia Staging Hub V2 | 0x68c931C9a534D37aa78094877F46fE46a49F1A51 |
References
Load these for deeper integration details:
references/frontend.md—SelfAppBuilderfull config,SelfQRcodeWrapperprops, deep linking withgetUniversalLink, disclosure optionsreferences/backend.md—SelfBackendVerifierconstructor details,DefaultConfigStorevsInMemoryConfigStore, verification result schema, dynamic configsreferences/contracts.md—SelfVerificationRootinheritance pattern, Hub V2 interaction,setVerificationConfigV2,customVerificationHook,getConfigId,userDefinedDatapatterns