Web SDK
Mobile apps and WebView
Show the verification widget inside your mobile app.
The widget is a web page, so a mobile app either shows it in a WebView or opens it in the system browser. This page lists what to configure so that the camera and the check work.
Which option to choose
| Option | When it fits | What to configure |
|---|---|---|
| A page with the widget in a WebView | The check must run inside the app. | Camera permission in the app and in the WebView, see below. |
| A direct link in the system browser, such as Safari View Controller or Custom Tabs | The simplest path, with no WebView setup. | The mobile redirect address in the scenario, see the section on the direct link below. |
| A page with the widget inside an iframe | The widget sits on a page inside a frame. | allow="camera" on the frame. |
Requirements for every option
- The page with the widget opens over HTTPS from your domain. A local file or a custom URL scheme does not work: the browser does not grant the camera, and the widget runs only on allowed domains.
- The domain of the page is in the allowed domains. See allowed domains and installation.
- The user grants the app camera access.
iOS, WKWebView
- Add the
NSCameraUsageDescriptionkey toInfo.plist, with a text the user understands. Without it the app cannot get the camera. - Turn on inline media playback with
allowsInlineMediaPlayback = true. Otherwise the camera preview opens in a full-screen player or does not appear. - Grant the camera to your own page in the delegate, so that the WebView does not ask again.
let config = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true
config.mediaTypesRequiringUserActionForPlayback = []
let webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self
webView.load(URLRequest(url: URL(string: "https://your-domain.example/verify")!))
// WKUIDelegate
func webView(_ webView: WKWebView,
requestMediaCapturePermissionFor origin: WKSecurityOrigin,
initiatedByFrame frame: WKFrameInfo,
type: WKMediaCaptureType,
decisionHandler: @escaping (WKPermissionDecision) -> Void) {
decisionHandler(origin.host == "your-domain.example" ? .grant : .prompt)
}
Android, WebView
- Declare the
CAMERApermission inAndroidManifest.xml. - Ask the user for
CAMERAat runtime, before you open the check. - Turn on JavaScript and page storage, and allow video autoplay.
- Grant the page camera access in
WebChromeClient.onPermissionRequest. Without it the WebView denies the page even when the app has the camera permission.
<uses-permission android:name="android.permission.CAMERA" />
webView.settings.apply {
javaScriptEnabled = true
domStorageEnabled = true
mediaPlaybackRequiresUserGesture = false
}
webView.webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
val video = PermissionRequest.RESOURCE_VIDEO_CAPTURE
if (request.origin.host == "your-domain.example" &&
request.resources.contains(video)) {
request.grant(arrayOf(video))
} else {
request.deny()
}
}
}
webView.loadUrl("https://your-domain.example/verify")
In-app browsers of messengers and social networks
A link opened inside a messenger or a social network lands in its built-in browser, where camera access can be restricted. If the check does not start, ask the user to open the link in the system browser. In your own app, use Safari View Controller on iOS and Custom Tabs on Android: the camera works there as in a regular browser.
Inside an iframe
If the page with the widget is itself opened in an iframe, allow the camera for the frame:
<iframe src="https://your-domain.example/verify" allow="camera"></iframe>
The inline mode with mountElementId does not work inside a cross-origin iframe. See installation.
Direct link with a return to the app
Instead of embedding the widget, open the check with a direct link in the system browser, Safari View Controller or Custom Tabs. The link has the form <verification page>/<scenarioId>/<encrypted clientKey>. See installation and working with clientKey.
In the main settings of the scenario, set the mobile redirect address on success: an address that your app can intercept, for example a universal link or an app link on your domain. When the check ends, the widget goes to this address and appends ?sessionId=<session id>&status=<final status>. On success this happens automatically after 5 seconds, and on any result through the return button on the result screen. The app intercepts the address, closes the browser and shows the next step.
The status in the address is a hint for the interface. Take the result on your server from the webhook or from session status.
If the camera does not start
| Symptom | What to check |
|---|---|
| The widget shows the screen that asks to allow the camera | The camera permission of the app in the phone settings. On Android, onPermissionRequest. |
| On iOS the preview opens full screen or is black | allowsInlineMediaPlayback = true. |
| The widget does not open on the page | The page is on HTTPS and the domain is in the allowed domains. |
| It fails only in the built-in browser of a messenger | Ask the user to open the link in the system browser. |
Questions, answered plainly
Is there a separate mobile SDK?
This documentation covers the web widget. To use it in an app, show the page that hosts the widget in a WebView or open it in the system browser.
Can the widget run from a local file in the app?
No. The page must open over HTTPS from an allowed domain, because the browser does not grant the camera otherwise.