> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.withverifa.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.withverifa.com/_mcp/server.

# Mobile SDK

> Native identity verification for iOS, Android, and React Native.

Verifa's mobile SDKs provide native document capture, selfie collection, and
liveness detection for iOS, Android, and React Native applications. The SDK
handles the camera UI, image quality checks, and fraud signal collection with a
native look and feel.

## Platforms

| Platform     | Package                             | Min version           |
| ------------ | ----------------------------------- | --------------------- |
| iOS          | `VerifaSDK` (Swift Package Manager) | iOS 14+               |
| Android      | `com.verifa:sdk` (Maven Central)    | API 24+ (Android 7.0) |
| React Native | `@verifa/react-native-sdk`          | RN 0.72+              |

## How it works

1. Your server creates a session via the API
2. Pass the session token to the mobile SDK
3. The SDK presents native capture screens
4. On completion, the SDK returns control to your app
5. Your server receives the result via webhook

## Integration flow

### Step 1: Create a session (server-side)

```bash
curl -X POST https://api.withverifa.com/api/v1/sessions \
  -H "X-API-Key: vk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "external_ref": "user_abc123",
    "country": "US"
  }'
```

Pass the session `id` and token to your mobile app.

### Step 2: Initialize the SDK

#### iOS (Swift)

```swift
import VerifaSDK

let config = VerifaConfig(
    sessionToken: "tok_abc123...",
    environment: .production
)

let verifa = Verifa(config: config)

verifa.start(from: self) { result in
    switch result {
    case .completed(let sessionId):
        print("Verification completed: \(sessionId)")
    case .cancelled:
        print("User cancelled")
    case .error(let error):
        print("Error: \(error)")
    }
}
```

#### Android (Kotlin)

```kotlin
import com.verifa.sdk.Verifa
import com.verifa.sdk.VerifaConfig

val config = VerifaConfig(
    sessionToken = "tok_abc123...",
    environment = VerifaEnvironment.PRODUCTION
)

Verifa.start(this, config) { result ->
    when (result) {
        is VerifaResult.Completed -> {
            Log.d("Verifa", "Completed: ${result.sessionId}")
        }
        is VerifaResult.Cancelled -> {
            Log.d("Verifa", "User cancelled")
        }
        is VerifaResult.Error -> {
            Log.e("Verifa", "Error: ${result.error}")
        }
    }
}
```

#### React Native

```javascript
import { Verifa } from '@verifa/react-native-sdk';

try {
  const result = await Verifa.start({
    sessionToken: 'tok_abc123...',
    environment: 'production',
  });

  if (result.status === 'completed') {
    console.log('Verification completed:', result.sessionId);
  }
} catch (error) {
  console.error('Verification error:', error);
}
```

### Step 3: Handle the result

The SDK callback tells you when capture is complete. The actual verification
result comes via your server's webhook:

```json
{
  "event": "session.approved",
  "created_at": "2026-02-01T12:05:00Z",
  "idempotency_key": "idk_a1b2c3d4e5f6...",
  "data": {
    "session_id": "session_abc123",
    "external_ref": "user_abc123",
    "status": "approved",
    "is_sandbox": false
  }
}
```

Or poll from your server:

```bash
curl https://api.withverifa.com/api/v1/sessions/session_abc123/result \
  -H "X-API-Key: vk_live_your_key_here"
```

## SDK configuration

### Fetch runtime config

The SDK fetches its configuration from the server on initialization:

```
GET /api/v1/sdk/config
```

This returns theming, feature flags, and required capture steps based on the
session's workflow.

### Theming

Customize the SDK appearance to match your app:

```swift
let config = VerifaConfig(
    sessionToken: "tok_abc123...",
    environment: .production,
    theme: VerifaTheme(
        primaryColor: UIColor(hex: "#4f46e5"),
        backgroundColor: .white,
        cornerRadius: 12
    )
)
```

Server-side theming is also available — configure in the dashboard under
**Settings > Organization** (Theming section) and it applies to all SDK sessions.

## Native fraud signals

The mobile SDK collects device-specific fraud signals not available in the web
capture flow:

| Signal                   | Description                                             |
| ------------------------ | ------------------------------------------------------- |
| Root/jailbreak detection | Detects rooted Android or jailbroken iOS devices        |
| Emulator detection       | Identifies virtual devices and emulators                |
| Debugger detection       | Detects attached debuggers                              |
| Screen recording         | Detects active screen capture or recording              |
| Camera injection         | Detects virtual camera apps injecting fake video        |
| Device attestation       | Validates device integrity via platform APIs            |
| Touch pressure           | Analyzes touch pressure patterns (zero pressure = bot)  |
| Gyroscope stability      | Detects unnaturally stable gyroscope (no hand movement) |
| Install source           | Detects sideloaded apps (not from official app store)   |

These signals are automatically submitted alongside the standard behavioral,
device, and network signals.

## Capture screens

The SDK presents these screens in sequence:

1. **Consent** — Biometric processing consent
2. **Document type** — Select ID type (passport, driver's license, etc.)
3. **Document capture** — Native camera with alignment guides, auto-capture, and
   quality feedback
4. **Selfie capture** — Front-facing camera with face alignment
5. **Liveness challenge** — Randomized challenges (blink, smile, head turn)
6. **Additional data** — Email, phone, address (if required by workflow)

The SDK skips screens that aren't required by the workflow's `data_requirements`.

## Permissions

The SDK requires camera permission. Request it before starting the SDK or let
the SDK handle the system prompt:

| Platform | Permission                                         |
| -------- | -------------------------------------------------- |
| iOS      | `NSCameraUsageDescription` in Info.plist           |
| Android  | `android.permission.CAMERA` in AndroidManifest.xml |

## Error handling

| Error                | Cause                           | Resolution                         |
| -------------------- | ------------------------------- | ---------------------------------- |
| `token_expired`      | Session token TTL exceeded      | Resume the session for a new token |
| `camera_unavailable` | No camera or permission denied  | Prompt user to grant camera access |
| `network_error`      | Lost connectivity during upload | SDK retries automatically          |
| `session_completed`  | Session already finished        | Create a new session               |

## Testing

In sandbox mode, the SDK allows you to select verification outcomes manually.
Create sessions with a sandbox API key (`vk_sandbox_*`) to enable this.

## Related

* [Choosing an Integration Method](/getting-started/choosing-an-integration-method) — Compare SDK
  vs web capture vs API-only
* [Web Capture Flow](/integration-guides/web-capture-flow) — Hosted capture for web apps
* [Fraud Signals](/best-practices/fraud-signals) — All signals including mobile-specific
* [Sessions](/core-concepts/sessions) — Session lifecycle and result retrieval