Integrate Reclaim Protocol end to end using our agent
logoReclaim Protocol Docs

Usage

NodeJS SDK for Reclaim Protocol

Quickstart

We will be creating two endpoints

  1. Start Verification
  2. Process Verification

The two endpoints are one journey. Here's the shape end-to-end:

  1. Backend — create the request. ReclaimProofRequest.init(...) → configure (callback, context) → export the whole config with toJsonString() and send it to your frontend.
  2. Frontend — launch verification. Import request with ReclaimProofRequest.fromJsonString(...), then triggerReclaimFlow() (auto-picks extension/portal/app) if you want verifications from your website. If your frontend is a native mobile app, using an in-app SDK, feed the same JSON config to its startVerificationFromJson instead.
  3. Receive results — pick one:
    • On the client via startSession({ onSuccess, onError }) — simplest, good for demos.
    • On your backend via setAppCallbackUrl(...)recommended for production, since proofs must be verified server-side anyway. This must be done before sending request to frontend.
  4. Backend — verify. verifyProof(proofs, ...) → run your business logic.

Import the library

import { ReclaimProofRequest } from '@reclaimprotocol/js-sdk';

Part 1: Start Verification Endpoint

Init

const reclaimProofRequest = await ReclaimProofRequest.init(
    process.env.RECLAIMPROTOCOL_APP_ID,
    process.env.RECLAIMPROTOCOL_APP_SECRET,
    'ff4d7afe-4b78-4795-9429-d20df2deaad7' // Example. Replace with provider ID
)
  • You can get the RECLAIMPROTOCOL_APP_ID and RECLAIMPROTOCOL_APP_SECRET using this guide
  • The PROVIDER_ID is the proof you want the user to generate. You can see all the available providers here. If you are just testing the flow, you can use the provider id ff4d7afe-4b78-4795-9429-d20df2deaad7.

Success Callback

reclaimProofRequest.setAppCallbackUrl(url, true);
// true - sets contentType to JSON

This is the endpoint to which the proofs will be submitted after the verification - this is where you will process the verification. We will define this endpoint in the next section.

[!TIP] Recommended for production. Once setAppCallbackUrl is set, proofs are delivered directly to your backend, so you can verify them server-side without trusting the client. When a callback URL is set, the frontend onSuccess fires with an empty array [] (the proofs went to your backend, not the browser). Notify the frontend of completion over WebSocket/SSE/polling once your backend has received and verified the proofs. You can also set setCancelCallbackUrl(...) to be told when the user cancels.

Set Context

You can set context to the proof request that helps identify the request when you receive it back in the callback once the proof is generated.

const address = "unique-user-id"; 
const message = "some meta data for processing on callback";
reclaimProofRequest.setContext(address, message)
  • address: this is usually a unique identifier for the user. This could be an email address, a wallet address, or just a session id generated on your system. Set the variable you'd need to identify the user in the callback endpoint, when the proof is sent to your backend.
  • message: this is an open field where you can add any other information that you want passed around from the build request to the callback endpoint. You can stringify jsons here for convenience.

Both context address and context message are tamper resistant. Even if the user tries to edit one byte, the proof verification will fail.

Open verification

After configuring your verification request in ReclaimProofRequest object on your NodeJs backend, you can export entire config as a JSON string and send it to your frontend.

const exportedProofRequestJsonString = reclaimProofRequest.toJsonString();

This can be used to create a ReclaimProofRequest using same SDK on frontend where you can trigger a web-based verification or you can use this config to start an in-app verification journey using our in-app SDK.

Option A: Web Frontend Web verification journey

To continue on web frontend, with @reclaimprotocol/js-sdk in your frontend dependencies, you have to import reclaim's proof request json string to make ReclaimProofRequest on frontend

const reclaimProofRequest = ReclaimProofRequest.fromJsonString(configJson);

In SDK, ReclaimProofRequest provides a triggerReclaimFlow() method that automatically handles the verification process for web-based verification across different platforms and devices. This method intelligently chooses the best verification method based on the user's environment.

How to use triggerReclaimFlow()

The triggerReclaimFlow() method supports two verification modes via verificationMode:

  • 'portal' (default): Opens a new reclaim web page for remote browser verification. Opens reclaim web page in a new tab by default, or embeds reclaim web page in an iframe when target is provided.
  • 'app': Opens Reclaim's Verifier app to do verification on client mobile device.

The method returns a FlowHandle that lets you close the flow programmatically:

  1. Portal flow (default) — opens in new tab
const handle = await reclaimProofRequest.triggerReclaimFlow();
handle.tab;    // Window reference to the opened tab
handle.close(); // close tab and stop polling
  1. Embedded — portal loads inside a DOM element as an iframe
const handle = await reclaimProofRequest.triggerReclaimFlow({
  target: document.getElementById('reclaim-container')
});
handle.iframe; // HTMLIFrameElement reference
handle.iframe?.style.height = '700px'; // customize the iframe
handle.close(); // remove iframe and stop polling
  1. Verifier app flow
const handle = await reclaimProofRequest.triggerReclaimFlow({
  verificationMode: 'app',
  canUseDeferredDeepLinksFlow: true
});
handle.close(); // stop polling

[!TIP] Strongly recommended: If you are NOT using portals or in app sdk, enable canUseDeferredDeepLinksFlow when starting verification on the web frontend. Using this prefers the use of deferred deep links. This will be enabled by default in future updates.

Receiving proofs on the client

For simple cases you can receive the generated proofs directly in the browser by calling startSession(). It launches the flow and polls until proofs are generated (or an error occurs):

await reclaimProofRequest.startSession({
  onSuccess: (proofs) => {
    // `proofs` is a single Proof when one proof is generated, or Proof[] otherwise.
    // NOTE: it is an empty array `[]` when a callback URL is set — proofs went to your backend.
    console.log('Verification success', proofs);
  },
  onError: (error) => {
    // `error` is a typed Error
    console.error('Verification failed', error.message);
  },
});
 
// You can read the session id at any time (e.g. to correlate with your backend):
const sessionId = reclaimProofRequest.getSessionId();

You can also pass richer options when creating the request on init, for example:

const reclaimProofRequest = await ReclaimProofRequest.init(APP_ID, APP_SECRET, PROVIDER_ID, {
  log: true,               // diagnostic logging
  useAppClip: true,        // allow the Verifier App Clip / Instant App
  launchOptions: {
    verificationMode: 'app', // 'portal' (default) or 'app'
    canUseDeferredDeepLinksFlow: true,
  },
});

[!TIP] Receiving proofs on the client is convenient, but for production you should route proofs to your backend with setAppCallbackUrl(...) and verify them there. See Success Callback.

Option B: In App Verification Flow

If you have an app, you can integrate one of reclaim's in-app SDK for embedding reclaim's entire verification experience in your native app.

This is available for Android, iOS, React Native, Flutter & Capacitor. To learn more, go to InApp Integration docs.

You can reuse the same toJsonString() config produced on your backend: pass it to the in-app SDK's startVerificationFromJson to launch the native verification experience — no need to re-build the request on the client.

You can follow start verification documentation for each platform to learn more about integrating with them. For example, React Native.

Store the Provider Version

  const { providerId, providerVersion } = reclaimProofRequest.getProviderVersion();
  • Store (providerId, providerVersion) corresponding to this user's uuid that you stored in address. You will need this providerVersion

More options

Part 2: Process Verification endpoint

Be sure to expose this endpoint over the public internet. If testing locally, use Ngrok

Replay protection

verifyProof is stateless — it confirms a proof is cryptographically valid, but it cannot know whether you've seen that proof before or whether it belongs to a session you actually started. For any flow where replay or tampering matters, the caller is responsible for:

  1. Match the session — verify the proof's sessionId (from the parsed context, see Continue Business Logic) matches a session your backend initiated for this user.
  2. Reject duplicates — persist accepted sessionIds and refuse a proof whose sessionId you've already accepted.
  3. Require hardware attestation — pass teeAttestation: { appSecret } to verifyProof (see Verify TEE Attestation) so tampered or replayed proofs fail verification.

Verify Proofs

import { verifyProof } from '@reclaimprotocol/js-sdk';

The easiest way is to use getProviderVersion() which returns the provider ID and exact version used in the session — pass it directly as the config:

const proofs = await request.json();
const providerVersion = reclaimProofRequest.getProviderVersion();
const { isVerified, data, error } = await verifyProof(proofs, providerVersion);
if (isVerified) {
  console.log("Proof is valid");
} else {
  console.log("Proof is invalid, reason:", error);
}

Or, by manually providing the provider details:

const { isVerified, data } = await verifyProof(proofs, {
  providerId: PROVIDER_ID,
  providerVersion: "1.0.0", // The exact provider version used in the session
  allowedTags: ["ai"] // Optionally allow patches from ai
});

Or, with a known hash:

const { isVerified, data, error } = await verifyProof(proofs, { hashes: ['0xAbC...'] });

You can get the provider version:

Continue Business Logic

const { context, extractedParameters } = data[0];
// Note if there are multiple proofs, you will have to iterate over data[]
  • context.address & context.message: Same as address and message set in Set Context. Use this to map user to verification.
  • extractedParameters: JSON object of all the data that has been extracted and verified. You can see the structure of each provider's response in the Provider Explorer.

For a full, field-by-field reference of the verifyProof result and the raw proof object (including claimData, the parsed context, signatures, witnesses and TEE attestation), see the Anatomy of messages data dictionary.

More options

Source code