iOS WKWebView requirements

Use this guide when your iOS app opens an ID.me OAuth 2.0 verification workflow in a WKWebView. iOS integrations must support camera permission prompts for document capture, selfie capture, and liveness checks.

Verification stages

Document upload starts when the user clicks a document upload or Take Photo button. If live document capture is required, the app should confirm camera access every time before sending the user to the capture step.

Selfie and liveness capture require camera access. There is no gallery-upload alternative for these steps, so permission denial must keep the user in a recoverable state with a retry or settings path.

Required permission text

Add camera usage text to Info.plist.

Info.plist
1<key>NSCameraUsageDescription</key>
2<string>ID.me needs camera access to capture your identity document.</string>

WKWebView setup

Configure WKWebView for inline media capture.

iOS WKWebView setup
1let configuration = WKWebViewConfiguration()
2configuration.allowsInlineMediaPlayback = true
3configuration.mediaTypesRequiringUserActionForPlayback = []
4
5let webView = WKWebView(frame: .zero, configuration: configuration)

Camera permission gate

Before sending a user into a camera-based verification workflow, check camera authorization. Do this every time the user starts document capture, selfie capture, liveness capture, or any SDK step that requires the camera. If permission is denied, show guidance before the user reaches the capture step.

iOS camera permission gate
1func continueWhenCameraIsAvailable() {
2 switch AVCaptureDevice.authorizationStatus(for: .video) {
3 case .authorized:
4 openIdmeVerification()
5 case .notDetermined:
6 AVCaptureDevice.requestAccess(for: .video) { granted in
7 DispatchQueue.main.async {
8 granted ? self.openIdmeVerification() : self.showCameraDeniedMessage()
9 }
10 }
11 case .denied, .restricted:
12 showCameraSettingsMessage()
13 @unknown default:
14 showCameraDeniedMessage()
15 }
16}

Send the user to app settings when camera access has been denied.

iOS app settings
1func openAppSettings() {
2 guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
3 UIApplication.shared.open(url)
4}

When the app becomes active again, re-check camera permission before continuing.

iOS settings return
1override func viewDidLoad() {
2 super.viewDidLoad()
3
4 NotificationCenter.default.addObserver(
5 self,
6 selector: #selector(appDidBecomeActive),
7 name: UIApplication.didBecomeActiveNotification,
8 object: nil
9 )
10}
11
12@objc private func appDidBecomeActive() {
13 guard waitingForCameraSettingsReturn else { return }
14 waitingForCameraSettingsReturn = false
15
16 if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
17 openIdmeVerification()
18 } else {
19 showCameraSettingsMessage()
20 }
21}

If your app exposes an ID.me WebView bridge, let the page request the same settings action.

iOS WKWebView settings bridge
1final class VerificationViewController: UIViewController, WKScriptMessageHandler {
2 private lazy var webView: WKWebView = {
3 let configuration = WKWebViewConfiguration()
4 configuration.userContentController.add(self, name: "idmeNative")
5 return WKWebView(frame: .zero, configuration: configuration)
6 }()
7
8 func userContentController(
9 _ userContentController: WKUserContentController,
10 didReceive message: WKScriptMessage
11 ) {
12 guard message.name == "idmeNative",
13 let body = message.body as? [String: String],
14 body["action"] == "openAppSettings",
15 body["permission"] == "camera" else {
16 return
17 }
18
19 openAppSettings()
20 }
21}

Only register native message handlers for trusted WebView content. Remove handlers when the WebView is deallocated if the same controller may load untrusted pages.

Keep iOS file input activation directly tied to the user’s tap. Calling a file input after an asynchronous JavaScript permission check can cause the picker to do nothing because iOS no longer treats it as user-initiated.

Document upload

When current-device upload is allowed, iOS may present camera and gallery options through the system file picker. When live capture is required by policy, do not present gallery upload as an alternative native path.

For live document capture:

  • Confirm camera permission every time before routing the user to the capture step.
  • Keep file input activation tied to the user tap.
  • Show native guidance if permission is denied.
  • Provide an app settings path if permission has been permanently denied.
  • Re-check permission when the user returns from app settings before continuing.

Liveness and selfie capture

Start selfie or liveness capture only after camera permission is granted. If the user denies access, show native guidance before starting the ID.me liveness or selfie capture step.

Testing checklist

  • Grant camera permission and complete document upload.
  • Deny camera permission once, retry, grant permission, and complete document upload.
  • Permanently deny camera permission and confirm the app settings path works.
  • Disable camera permission in app settings, return to a new verification session, and confirm the app re-checks permission before opening capture.
  • Return from app settings, re-check camera permission, and continue capture only when permission is granted.
  • Confirm any WebView settings bridge is restricted to trusted ID.me pages.
  • Confirm document file input opens directly from a user tap.
  • Complete selfie or liveness capture after granting permission.
  • Deny permission before selfie or liveness and confirm the app does not start capture.