@getvouch/mobile-sdk
v0.1.8
Published
React Native SDK for the Vouch proving flow
Downloads
10,715
Readme
@getvouch/mobile-sdk
The Vouch React Native SDK embeds the full Vouch verification flow in your app: screens, state machine, and backend transport that take a proof request from start to finished proof. To learn what Vouch is and how verification works, see the Vouch docs — this README covers integrating the SDK.
Requirements
- React Native 0.81.5 – 0.83.x, React 19.1 – 19.2
- iOS 16.4 or higher
- Android API 26 (Android 8) or higher
- Peer dependencies the host app must provide:
react-native-safe-area-context(>=5.6 <6),react-native-svg(>=15.12 <16),react-native-video(>=6.17 <7),react-native-webview(>=13.15 <14)
The peer ranges in package.json are authoritative — your package manager will warn if your versions fall outside them.
Installation
npm install @getvouch/mobile-sdkThe SDK autolinks its native module on both platforms (iOS via CocoaPods, Android via Gradle). No manual native setup is needed for regular web-proof verification.
Usage
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>
);
}apiKey— your customer API key, required to create new proof requests. See First steps for where to find it.customerId— required only by the Modal API; the hook API takes it per flow insidecreateProofRequest.baseUrl— optional, defaults tohttps://app.getvouch.io.languageCodeOverride— optional BCP 47 tag (en,pl-PL, …) overriding the device language for modal starts; the hook API takes it per flow onstartProve.webviewDebuggingEnabled— optional, off 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 />;
}3. Observe the state
state.status moves through idle → launching → processing → proving → success, or ends in error or cancelled (user closed the flow; carries the requestId it ended). 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 flow.
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
cancelledstatus, carrying therequestIdit ended. Compare that id against your own flow's before acting on it, so a shared provider's stalecancelledfrom an earlier flow does not move the wrong screen. - Modal API:
start/startHeadlessreject withdescription: "Vouch flow was closed"and reason0.
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 (VouchStartParams has no requestId, so the modal API cannot); 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.
Modal API
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 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.
Video verification (optional)
Some data sources use video verification instead of a cryptographic web proof. Regular web-proof flows need no extra setup, and Android video verification autolinks too. Video verification on iOS additionally requires the SDK's Expo config plugin, which adds the App Group entitlement and the VouchBroadcast screen-recording extension:
{
"expo": {
"plugins": [["@getvouch/mobile-sdk", { "appGroupIdentifier": "group.<your-bundle-id>" }]]
}
}appGroupIdentifier is optional and defaults to group.<your-bundle-id>.vouch. The plugin changes the native project, so after adding it regenerate the native directories with npx expo prebuild, then rebuild and install the app — npx expo run:ios, or a new EAS build. Reloading JS is not enough to pick up the entitlement.
If a data source runs in video mode and the plugin is missing, the SDK fails the flow immediately with a clear error (and, in development, logs the exact fix) instead of failing after the user has recorded.
Error codes
A modal-API rejection carries a numeric VouchError.reason. The full set is unchanged from the legacy SDK:
| Code | Meaning | | ---- | --------------------------------- | | 0 | Data source or customer not found | | 1 | Outdated SDK version | | 2 | Failed to create verification | | 3 | Background timeout | | 4 | Request too large | | 5 | Data source misconfigured | | 6 | Verification failed | | 7 | Verification upload failed | | 8 | Attachment reupload failed | | 9 | Verification ID already taken | | 10 | Network connection lost | | 11 | Processing timeout | | 12 | Wrong API key | | 13 | Internal server error | | 14 | Provider 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.
Migrating from @getvouch/react-native-sdk
The legacy @getvouch/react-native-sdk (latest 0.9.9) wrapped prebuilt native SDKs: the io.getvouch:android-sdk Gradle artifact and the vouch-ios-sdk pod. This package replaces that native stack with React Native and JavaScript over @vouch/prover-mobile-js. It is a different package on a different release line, so there is no version bump that carries you across.
The Modal API exists to keep the rest of the migration small. start, startHeadless, VouchStartParams (dataSourceId, webhookUrl, inputs, metadata), the downloadingConfig → sniffingRequests → proving → finished progress strings, headless showing UI only during sniffingRequests, and the numeric error codes all carry over unchanged. VouchSuccess still carries proofId, and now also an optional redirectBackUrl.
What you have to change:
Swap the package and install four peer dependencies. The legacy package peered only
reactandreact-native; this one also needsreact-native-safe-area-context,react-native-svg,react-native-video, andreact-native-webview(see Requirements).Replace
initialize()with the provider.initialize()andisInitialized()are gone, soVouchSDK.initialize(...)now throws aTypeError. (isSupported()is gone too, though0.9.9never actually exported the method its docs described.) Move the same configuration ontoVouchVerifierProvider, mounted once at the app root:// before await VouchSDK.initialize({ customerId: "CUSTOMER_ID", apiKey: "API_KEY", languageCodeOverride: "pl-PL" }); // after <VouchVerifierProvider customerId="CUSTOMER_ID" apiKey="API_KEY" languageCodeOverride="pl-PL"> <YourScreens /> </VouchVerifierProvider>;Rework error handling.
VouchError.proofIdis now optional: present once a proof request exists, omitted for failures before that, where the legacy SDK sent""— soerror.proofId.lengththrows. The legacy-1("SDK not initialized or internal error") is never emitted; a missing or incompletely configured provider reports14instead. AndstartHeadlessnow rejects with the sameVouchErrorobject asstart, where the legacy one rejected with a bareErrorcarrying noreasonordescription.Re-check what
destroy()does for you. The legacydestroy()tore down initialization state and forced a freshinitialize(). This one only clears WebView cookies and leaves the mounted provider usable — see Cleanup.Re-check your platform floors. React Native 0.81.5 – 0.83.x and React 19.1 – 19.2 are enforced peer ranges, where the legacy package accepted anything. Android's minimum drops from API 33 to API 26, and iOS no longer needs
use_frameworks!in your Podfile.
