@surtai/idv-rn
v0.1.0
Published
Official React Native SDK for Surt IDV, KYC identity verification
Downloads
217
Readme
@surtai/idv-rn
Official React Native SDK for Surt IDV: KYC identity verification.
The SDK opens the verify app inside a fullscreen react-native-webview modal. It bridges the verify app's iframe-style postMessage events to React Native callbacks, so the same contract works on web and native.
Install
npm install @surtai/idv-rn react-native-webview
# or
pnpm add @surtai/idv-rn react-native-webview
# or
yarn add @surtai/idv-rn react-native-webviewiOS Info.plist
<key>NSCameraUsageDescription</key>
<string>Used to capture identity documents and selfies for verification.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Used during liveness checks.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Used to verify your location during identity verification.</string>For Expo (managed workflow), put these under expo.ios.infoPlist in app.json.
Android AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />For Expo, put these under expo.android.permissions in app.json.
Quickstart
Mount the provider once at the app root:
import { SurtIDVProvider } from '@surtai/idv-rn';
export default function App() {
return (
<>
<RootNavigator />
<SurtIDVProvider />
</>
);
}Then trigger a session from anywhere:
Callback API
import { SurtIDV } from '@surtai/idv-rn';
const session = SurtIDV.init({
token: 'PORTAL_JWT',
onApproved: () => console.log('verified'),
onRejected: () => console.log('rejected'),
onCanceled: () => console.log('user closed'),
onError: (e) => console.error(e.message),
});
// close programmatically
session.destroy();Promise API
const result = await SurtIDV.verify({ token });
switch (result.status) {
case 'approved': /* user passed verification */ break;
case 'rejected': /* user failed verification */ break;
case 'manual_review': /* queued for human review */ break;
case 'support': /* user requested support */ break;
case 'canceled': /* user closed the modal */ break;
case 'expired': /* session expired */ break;
case 'error': /* console.error(result.error) */ break;
}Options
| Option | Type | Default | Notes |
|---|---|---|---|
| token | string | required | Portal JWT issued by core-dd. |
| baseUrl | string | https://identity.surt.com | Override the verify app origin. |
| lang | string | from token | Locale override. Supported: en, es, pt. |
Callbacks
All callbacks are optional. Each maps directly to a postMessage event from the verify app.
| Callback | Fires when |
|---|---|
| onReady() | The verify app loaded inside the WebView. |
| onApproved() | Verification passed. |
| onRejected() | Verification failed. |
| onManualReview() | Result deferred to human review. |
| onSupport() | User requested support / session abandoned. |
| onCanceled() | User tapped the close (X) button or swiped down. |
| onExpired() | Session expired. |
| onError(e) | Bad token, network error, unknown reason. e.message has details. |
API surface
import {
SurtIDV, // { init(opts), verify(opts) }
SurtIDVProvider, // mount once at app root
SurtIDVView, // render the WebView yourself
type SurtIDVInitOptions,
type SurtIDVInstance,
type SurtIDVVerifyOptions,
type SurtIDVVerifyResult,
type SurtIDVReason,
type SurtIDVViewProps,
} from '@surtai/idv-rn';Embedding directly
If you'd rather control presentation yourself, render <SurtIDVView> instead of using the provider:
import { SurtIDVView } from '@surtai/idv-rn';
import { Modal } from 'react-native';
<Modal visible={open} animationType="slide" presentationStyle="fullScreen" onRequestClose={() => setOpen(false)}>
<SurtIDVView
token={token}
onApproved={() => setOpen(false)}
onRejected={() => setOpen(false)}
onCanceled={() => setOpen(false)}
/>
</Modal>iOS reverification camera bug
The SDK sets these <WebView> props internally. If you ever wrap react-native-webview directly instead of using <SurtIDVView>, replicate them, otherwise reverification on iPhone 15/16 (iOS 17+) breaks because WKWebView caches camera permission state across mounts:
<WebView
ref={webViewRef}
// Required, fixes iOS reverification camera bug
incognito
mediaCapturePermissionGrantType="grant"
onLoadStart={() => webViewRef.current?.clearCache?.(true)}
// Required for camera/media
allowsInlineMediaPlayback
mediaPlaybackRequiresUserAction={false}
allowsProtectedMedia
javaScriptEnabled
domStorageEnabled
originWhitelist={['*']}
// Recommended
geolocationEnabled
androidLayerType="hardware"
/>incognito={true} is the main fix; the cache clear and mediaCapturePermissionGrantType="grant" are belt-and-suspenders for the iOS TCC permission cache.
How the postMessage bridge works
The verify web app emits events like window.parent.postMessage({ action: 'close', reason: 'approved' }, '*'). To make those events reach React Native, the SDK injects a small script before page load that overrides window.parent.postMessage to forward through ReactNativeWebView.postMessage. You don't need to do anything, this is automatic.
Known-good versions
| Package | Version |
|---|---|
| react-native | 0.81.5 |
| react-native-webview | 13.15.0 |
| react | 19.1.0 |
The SDK declares react-native-webview >= 13.15.0 as a peer dep, older versions don't support the incognito + clearCache combination needed for the iOS camera fix.
Related
@surtai/idv: same API for web (uses an iframe).- The verify app itself is at identity.surt.com.
