iOS
Present the verification flow from UIKit or SwiftUI (iOS 15+) and await a typed OkycResult.
Version0.1.1
Install
No third-party dependencies (UIKit, WebKit, AVFoundation, SwiftUI).
Swift Package Manager: in Xcode, choose File → Add Package Dependencies…, enter
https://github.com/okyc-team/okyc-ios and add the OKYC product. In a Package.swift:
// Package.swift of your app (or Xcode → File → Add Package Dependencies… → https://github.com/okyc-team/okyc-ios).
dependencies: [
.package(url: "https://github.com/okyc-team/okyc-ios.git", from: "0.1.0"),
],
targets: [
.target(name: "YourApp", dependencies: [.product(name: "OKYC", package: "okyc-ios")]),
]CocoaPods:
pod 'OKYC', '~> 0.1'Permissions
The flow uses the camera (documents, selfie) and may use the microphone. Add both usage strings to your
Info.plist:
<!-- The flow uses the camera (documents, selfie) and may ask for the microphone (liveness). -->
<key>NSCameraUsageDescription</key>
<string>We use the camera to capture your documents and a selfie to verify your identity.</string>
<key>NSMicrophoneUsageDescription</key>
<string>The verification flow may request microphone access for the liveness check.</string>Start the flow
Create the session on your backend and pass its url to the app.
let config = OkycConfig(
sessionURL: url, // the `url` your backend got from POST /v1/sessions
locale: nil, // "en" or "hi"; nil keeps the session's language
theme: theme, // .light, .dark or .system (default)
blockScreenshots: true, // cover the flow in the app switcher and while recording (default)
autoCloseDelay: 2, // seconds the result screen stays visible after `complete`; nil = stay open
presentation: .sheet // or .fullScreen
).okycVerification(
isPresented: $presenting, // set to true to present the flow
config: config,
onEvent: { event in handleEvent(event) },
onResult: { result in handleResult(result) } // called exactly once per presentation
)Also available: OkycViewController(config:) with a delegate (okyc(_:didReceive:),
okyc(_:didFinishWith:)), the SwiftUI modifier .okycVerification(isPresented:config:onEvent:onResult:), and
OkycView to embed the flow in your own container.
Options
| Option | Type | Default | Description |
|---|---|---|---|
sessionURL | string | required | The url returned by POST /v1/sessions. Never embed a secret API key in an app. |
locale | string | null | Flow language (en, hi); must be one of the workflow's languages. Sent as ?locale=. |
theme | light | dark | system | "system" | Colour scheme of the flow. Sent as ?theme=. |
allowedHosts | string[] | [] | Extra hosts the WebView may load (self-hosting). |
blockScreenshots | boolean | true | Android: FLAG_SECURE. iOS: cover the flow in the app switcher and while the screen is recorded. |
autoCloseDelay | duration_ms | 2000 ms | How long the result screen stays visible after complete before the SDK closes and returns completed. 0 or null = return the result immediately (no result screen). |
iOS also has: presentation (see the SDK README).
Results and events
private func handleResult(_ result: OkycResult) {
switch result {
case let .completed(sessionId, status):
// The applicant finished. Confirm the decision on your backend (webhook or GET /v1/sessions/:id).
show("completed \(sessionId) \(status)")
case let .cancelled(sessionId):
// Closed before finishing; the same session URL can be opened again.
show("cancelled \(sessionId ?? "-")")
case let .failed(code, message, _):
// `code` is one of OkycErrorCode (network_error, load_failed, …).
show("failed \(code) \(message)")
}
}private func handleEvent(_ event: OkycEvent) {
// Progress only (ids and statuses, never personal data). The result arrives in handleResult.
switch event.kind {
case .stepStarted, .stepCompleted: log.append("\(event.kind.rawValue) \(event.payload["step"] ?? "")")
case .error: log.append("error \(event.payload["code"] ?? "")") // recoverable; the flow keeps running
default: log.append(event.kind.rawValue)
}
}OkycResult is .completed(sessionId, status), .cancelled(sessionId) or .failed(code, message, sessionId) (sessionId is nil if the flow never loaded). Swipe-down
on the sheet, ✕, or the flow's own exit returns .cancelled. Event payload values are strings.
Failure codes on iOS:
| Code | Meaning |
|---|---|
invalid_config | Missing or malformed session URL or configuration. |
load_failed | The flow page failed to load (HTTP error or blank page). |
network_error | No connection or DNS/TLS failure while loading. |
navigation_blocked | Repeated navigation to non-allowlisted hosts. |
permission_denied | The camera permission was permanently denied and the flow cannot continue. |
flow_error | The flow reported an unrecoverable error. |
webview_unavailable | The WebView renderer crashed or is unavailable. |
presentation_failed | No view controller was available to present the flow. |
Theming and locale
theme (.light, .dark, .system) is sent as ?theme= and applied to the native chrome. locale is sent
as ?locale= before the #t= fragment and must be one of the workflow's languages. presentation is
.sheet (swipe down cancels) or .fullScreen.
Security defaults
- The session URL must use https; plain http is accepted only for
localhost,127.0.0.1and::1(otherwiseinvalid_config). - Messages are accepted only from the main frame of the session origin and must match protocol v1.
- The flow origin and DigiLocker stay inside the web view; other https links open in Safari; everything else is blocked.
- Camera and microphone are granted only to the flow origin, after the iOS permission.
- A non-persistent website data store, wiped when the flow finishes. The session URL is never logged.
- Web Inspector only in DEBUG builds.
- iOS can't block screenshots;
blockScreenshotshides the flow in the app switcher and while the screen is recorded or mirrored.
Troubleshooting
| Symptom | Fix |
|---|---|
OkycConfig(sessionURLString:) returns nil | The string isn't a valid session url. |
presentation_failed | Start from a view controller that is in the window hierarchy. |
| Camera prompt never appears | NSCameraUsageDescription is missing from Info.plist. |
Going live
- Create sessions with a
sk_live_…key on your backend; nothing changes in the app. - Decide on the webhook, not on
.completed.
Android
Run the verification flow in a hardened WebView from Kotlin (minSdk 24) and get a typed OkycResult.
React Native
A hardened react-native-webview wrapper (RN 0.74+) with a component, a modal and a promise API.
© 2026 Aiistic Technologies Private Limited. OKYC is a product of Aiistic Technologies Private Limited. Privacy notice