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
| Option | When it fits | What to configure |
|---|---|---|
| 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 |
| Direct link in the system browser (Safari View Controller, Custom Tabs) | The simplest path without WebView setup | Return URL in the scenario, see “Direct link with return” |
Page with the widget in an <iframe> | The widget sits on a page inside a frame | allow="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)
- Add the
NSCameraUsageDescriptionkey toInfo.plistwith a text the user understands. Without it the app cannot get the camera. - Enable inline video playback:
allowsInlineMediaPlayback = true. Otherwise the camera preview opens in a full-screen player or does not appear. - 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)
- Declare the
CAMERApermission inAndroidManifest.xml. - Request
CAMERAfrom the user at runtime, before opening the check. - Enable 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/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> - 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).
- When the check ends, the widget goes to this address and appends
?sessionId=<session id>&status=<final status>: onsuccessautomatically after 5 seconds, on any result — via the return button on the result screen. - 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
| Symptom | What to check |
|---|---|
| The widget shows the “allow camera access” screen | The 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 page | The page is on HTTPS, the domain is in “Allowed domains” |
| Fails only in a messenger’s built-in browser | Open the link in the system browser |