Mobile apps and WebView

The KYC widget runs in a browser, so a mobile app either embeds it in a WebView or opens it in the system browser. Below is what to configure so that the camera and the check work.

Which option to choose

OptionWhen it fitsWhat to configure
Page with the widget in a WebViewThe check must run inside the appCamera permission in the app and in the WebView, see below
Direct link in the system browser (Safari View Controller, Custom Tabs)The simplest path without WebView setupReturn URL in the scenario, see “Direct link with return”
Page with the widget in an <iframe>The widget sits on a page inside a frameallow="camera" on the frame

Common requirements

  • The page with the widget is opened over HTTPS from your domain. A local file or a non-standard URL scheme will not work: the browser will not grant the camera, and the widget works only on allowed domains.
  • The page domain is added in "Access" → "Allowed domains". Details — Connection.
  • The user grants the app camera access.

iOS (WKWebView)

  1. Add the NSCameraUsageDescription key to Info.plist with a text the user understands. Without it the app cannot get the camera.
  2. Enable inline video playback: allowsInlineMediaPlayback = true. Otherwise the camera preview opens in a full-screen player or does not appear.
  3. To stop the WebView from asking again for your own page, grant the permission in the delegate (iOS 15 and later).
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/kyc")!))

// 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)

  1. Declare the CAMERA permission in AndroidManifest.xml.
  2. Request CAMERA from the user at runtime, before opening the check.
  3. Enable JavaScript and page storage, and allow video autoplay.
  4. 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/kyc")

In-app browsers of messengers and social networks

A link opened inside a messenger or social network lands in its built-in browser, where camera access may be restricted. If the check does not start, ask the user to open the link in the system browser (Safari, Chrome). In your own app, use Safari View Controller on iOS and Custom Tabs on Android for the same purpose: the camera works there as in a regular browser.

Embedding in an iframe

If the page with the widget is itself opened inside an <iframe>, allow the camera for the frame:

<iframe src="https://your-domain.example/kyc" allow="camera"></iframe>

Inline mode (mountElementId) does not work inside a cross-origin iframe — see Connection.

Direct link with return to the app

Instead of embedding, you can open the check by a direct link in the system browser, Safari View Controller or Custom Tabs:

https://kyc.neuro-vision.ru/<scenarioId>/<encrypted clientKey>
  1. In the scenario's main settings, set the "Mobile redirect URL on success" — an address your app can intercept (for example, a universal link or App Link on your domain).
  2. When the check ends, the widget goes to this address and appends ?sessionId=<session id>&status=<final status>: on success automatically after 5 seconds, on any result — via the return button on the result screen.
  3. The app intercepts the address, closes the browser and shows the user the next step.

The status in the address is a hint for the interface. Take the check result on the server from the webhook or a session status request. How to build the link and encrypt clientKey — Connection and Working with clientKey.

If the camera does not start

SymptomWhat to check
The widget shows the “allow camera access” screenThe app’s camera permission in the phone settings; on Android — onPermissionRequest
The camera preview opens full screen or is black (iOS)allowsInlineMediaPlayback = true
The widget does not open on the pageThe page is on HTTPS, the domain is in “Allowed domains”
Fails only in a messenger’s built-in browserOpen the link in the system browser