vlayer logovlayer
React Native

Usage

Coming from @getvouch/react-native-sdk? The Modal API keeps the legacy VouchSDK.start / startHeadless calls working — see the migration guide for what changes.

Overview

The Vouch React Native SDK embeds the full verification flow in your app: screens, state machine, and backend transport that take a proof request from start to finished proof. Integration is hook-first: mount one provider, drive the flow with the useVouch hook, and render it with VouchScreen wherever your app decides to show it.

1. Mount the provider

Mount VouchVerifierProvider once at the app root. It owns the flow state; everything else renders under it.

import { VouchVerifierProvider } from "@getvouch/mobile-sdk";

function App() {
  return (
    <VouchVerifierProvider apiKey="API_KEY">
      <YourScreens />
    </VouchVerifierProvider>
  );
}
PropTypeRequiredDescription
apiKeystringYesYour customer API key, required to create new proof requests. See First steps for where to find it
customerIdstringNoRequired only by the Modal API; the hook API takes it per flow inside createProofRequest
baseUrlstringNoDefaults to https://app.getvouch.io
languageCodeOverridestringNoBCP 47 tag (en, pl-PL, …) overriding the device language for modal starts; the hook API takes it per flow on startProve
webviewDebuggingEnabledbooleanNoOff by default. Development builds are always inspectable; this opts release builds into Chrome DevTools / Safari Web Inspector too. Leave it off in production: the proof WebView holds the user's authenticated session with the data source

2. Start a flow and render it

Drive the flow with the useVouch hook and render it with VouchScreen:

import { useEffect } from "react";
import { VouchScreen, useVouch } from "@getvouch/mobile-sdk";

function ProveScreen() {
  const { state, startProve, reset } = useVouch();

  useEffect(() => {
    // a. Resume a proof request your backend already created:
    startProve({ requestId: "EXISTING_REQUEST_ID" });
    // b. …or create one on the fly:
    // startProve({
    //   createProofRequest: {
    //     customerId: "CUSTOMER_ID",
    //     dataSourceId: "DATA_SOURCE_ID",
    //     webhookUrl: "https://your-server.com/webhook",
    //     inputs: { INPUT_NAME: "value" },
    //   },
    // });
    return () => reset();
  }, [startProve, reset]);

  useEffect(() => {
    if (state.status === "success") {
      // state.result.proofId identifies the finished proof — navigate away here.
    }
  }, [state]);

  return <VouchScreen />;
}

startProve takes either { requestId } to resume an existing proof request, or { createProofRequest } to create one.

requestId is a string identifying a proof request your backend already created.

createProofRequest accepts:

ParameterTypeRequiredDescription
customerIdstringYesYour unique customer identifier from Vouch
dataSourceIdstringYesThe identifier for the data source to use for verification
webhookUrlstringNoThe URL where verification results will be sent
inputsObjectNoAdditional input parameters required by the data source
metadatastringNoAn optional value passed alongside the proof for easier identification

For detailed documentation on dataSourceId, webhookUrl, and inputs, see the getDataSourceUrl Parameters section.

3. Observe the state

state.status moves through idle → launching → processing → proving → success, or ends in error or cancelled (the user closed the flow; it carries the requestId of the flow it ended). While the status is idle, VouchScreen renders nothing.

Calling startProve again after any terminal state seeds a fresh flow — no explicit reset() needed; reset() returns the machine to idle without starting a new one.

4. Closing and re-entry

The user can leave the flow from the SDK's own chrome — the close control in the proof browser's header, the close on the video and error screens, or the Android hardware back button on any of those steps. Every one of them ends the flow the same way:

  • Hooks API: the flow lands on the terminal cancelled status, carrying the requestId it ended. Compare that id against your own flow's before acting on it, so a shared provider's stale cancelled from an earlier flow does not move the wrong screen.
  • Modal API: start/startHeadless reject with description: "Vouch flow was closed" and reason 0.

Two stages carry no close of their own: launching, while the proof request loads, and proving, where cancelling would throw away a proof that is nearly finished. In hooks mode nothing interrupts those stages — hardware back falls through to your own navigation, and it is your screen that decides what to do; in modal mode Android back dismisses the modal from any stage. proving continues without the flow UI on screen, so hiding your own screen during it is safe.

Closing discards the attempt — the proof request is not finished, and nothing is uploaded. To let the user try again, call startProve (or start) again; a modal host always starts a fresh proof request that way. Hooks hosts can also pass startProve({ requestId }) with the closed flow's id to re-enter that same proof request from the beginning instead of creating a new one; WebView cookies survive the close, so the user is usually still signed in to the data source. A request that already produced a proof cannot be reused — start a new one.

Hosts migrating from the legacy imperative SDK can use the provider-backed modal API instead of the hook. It presents the flow in a full-screen modal and resolves a promise, so no VouchScreen is mounted. The provider must carry both customerId and apiKey — without either, start rejects with reason 14:

import VouchSDK, { VouchVerifierProvider } from "@getvouch/mobile-sdk";

function App() {
  return (
    <VouchVerifierProvider customerId="CUSTOMER_ID" apiKey="API_KEY">
      <YourScreens />
    </VouchVerifierProvider>
  );
}

// Call this from a handler on a screen under the provider. `start` resolves the
// controller the mounted provider registers, so calling it at module scope —
// before that happens — rejects with reason 14.
async function verify() {
  const { proofId } = await VouchSDK.start({
    dataSourceId: "DATA_SOURCE_ID",
    webhookUrl: "https://your-server.com/webhook",
    inputs: { INPUT_NAME: "value" },
    metadata: "YOUR_OWN_REFERENCE", // optional, travels with the proof
  });

  return proofId;
}

VouchSDK.startHeadless(params, onProgress?) runs the same flow and takes the same params, but only presents UI during the sniffingRequests stage; it reports progress as downloadingConfig → sniffingRequests → proving → finished.

Both reject with a plain VouchError object — { reason, description, proofId? }, not an Error. A user who closes the flow rejects it too, with description: "Vouch flow was closed"; see Closing and re-entry and Error codes.

Cleanup

Call await VouchSDK.destroy() to remove WebView cookies. This works without a mounted provider. On Android it clears the dedicated Vouch WebView profile when the installed WebView provider supports profiles; older providers use the process default cookie store, so cleanup also removes cookies created by host WebViews. On iOS it clears the shared default WebKit cookie store, including cookies created by other WebViews in the host app. It does not clear other website data or cancel an active proof flow.

Error codes

A modal-API rejection carries a numeric VouchError.reason:

CodeDescription
0Data source or customer not found
1Outdated SDK version
2Failed to create verification
3Background timeout
4Request too large
5Data source misconfigured
6Verification failed
7Verification upload failed
8Attachment reupload failed
9Verification ID already taken
10Network connection lost
11Processing timeout
12Wrong API key
13Internal server error
14Provider missing or unconfigured

Code 0 doubles as the fallback for rejections without a more specific cause — including a cancelled flow — so branch on description rather than treating 0 as diagnostic.

Best Practice: Always handle both success and error cases. Log the proofId (when present) for debugging and user support purposes, even in error cases.