# Sumsub Integrate Msdk

> Integrate the Sumsub Mobile SDK (IdensicMobileSDK / SNSMobileSDK) into a native iOS or Android app — even when the user doesn't name the SDK (e.g. "add Sumsub/KYC to my iPhone app", "add KYC to my Android app", "show the verification screen", "launch Sumsub from a view controller / activity"). Detects the platform from the project (iOS Xcode/Swift vs Android Gradle/Kotlin) and follows the matching track. Covers install, permissions, init, token refresh, and presenting / launching the flow. SKIP for web (`sumsub-integrate-websdk`), backend / API-only token signing (`sumsub-api-generic`), theming (`sumsub-theme-msdk`), and React Native / Flutter (not supported — native iOS & Android only).

- Skill: `sumsub/sumsub-integrate-msdk` (Agent Skill, multi-file: 40 files)
- Install (CLI): `npx skillmds@latest add sumsub/sumsub-integrate-msdk`
- Raw SKILL.md: https://api.skillmd.com/api/skills/sumsub/sumsub-integrate-msdk/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: sumsub (https://skillmd.com/u/sumsub)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/sumsub/sumsub-integrate-msdk

---


# Sumsub — Mobile SDK integration (iOS & Android)

Embed Sumsub KYC into an existing native app via the **`IdensicMobileSDK`** framework
(main class **`SNSMobileSDK`**), from dependency install to presenting / launching the
verification flow — on **iOS** (Swift) or **Android** (Kotlin).

This is the **trunk**: read the always-on sections below (intake, asking-vs-doing),
detect the platform, then use the [decision table](#how-to-navigate-this-skill) to open
**only** the branch files that match the platform, the project, and the user's answers.

## Intake — ask these three questions first, in one message

Before touching any project file, ask all three together:

1. **Launch point.** "From which screen should the Sumsub flow open? Please share the
   class name or describe the screen." — *iOS:* a ViewController or SwiftUI view;
   *Android:* an Activity, Fragment, or Composable.

2. **Access token source.** "Does your app already have a way to fetch a Sumsub
   access token from your backend? (If yes, share the function name, endpoint URL,
   or service class. If not, I'll add a placeholder you can fill in when your
   backend is ready.)"

3. **Optional modules.** "The base SDK covers standard verification flows and is **always installed**. On top of it, do
   you need any of these
   add-ons?
    - **NFC** (passport / eMRTD chip reading) — *iOS:* `MRTDReader`; *Android:* the `nfc` module – read the chip on
      biometric passports
    - **VideoIdent** — live video call with a moderator
    - **EID** — German eID card reading
    - **Fisherman / Device Intelligence** — fraud signals *(iOS: optional
      module; **Android: bundled in the base SDK since 1.43.0** — nothing to add)*
      Skip them if you're not sure — they can be added later."

   Modules are **purely additive**. In a multi-select, list **only the modules** —
   an empty selection already means "base only"; don't add "base only" as a
   co-selectable peer.

Do **not** ask about: the App Token or the secret key — those are server concerns
that never touch the app.

## Asking vs doing — keep approvals meaningful

- **Read-only is free** — scan / grep / read `Info.plist`, `AndroidManifest.xml` & build files without asking.
- **Batch mutations into one approval**, not one per line ("I'll add these 3 Info.plist
  keys [list] + this call site [diff] — apply?").
- **Ask explicitly only for:** editing existing app code, project-mutating commands
  (`pod install`, a Gradle sync), anything irreversible, and decisions you couldn't settle in intake.

## Detect the platform (do this before opening any branch file)

Decide whether this is an **iOS** or **Android** project — the install steps, the
permission model, and the generated language all differ. Read-only.

```bash
# iOS markers
find . -maxdepth 3 \( -name '*.xcodeproj' -o -name '*.xcworkspace' -o -name 'Podfile' -o -name 'Package.swift' \) 2>/dev/null
# Android markers
find . -maxdepth 3 \( -name 'build.gradle' -o -name 'build.gradle.kts' -o -name 'settings.gradle*' -o -name 'AndroidManifest.xml' \) 2>/dev/null
```

- **iOS only** (`.xcodeproj` / `Package.swift` / `Podfile`, no Gradle) → **iOS track**.
- **Android only** (`build.gradle[.kts]` / `AndroidManifest.xml`, no Xcode) → **Android track**.
- **Both present** (a monorepo, or a React-Native / Flutter shell with native folders) →
  report both and **ask which platform to integrate.** One platform per run. (React
  Native / Flutter wrappers themselves are out of scope — this skill targets the native
  SDKs; the Step-1 scan bails on a detected wrapper.)
- **Neither** → ask the user to point at the app's source root.

Confirm the detected platform if there was any ambiguity, then follow the matching track.

## How to navigate this skill

After intake, open ONLY the rows that match the **detected platform**, the project (from
Step 1), and the user's intake answers. Each branch file is self-contained and ends with
a **Next** pointer. A letter (2A/2B, 6A/6B) marks a branch — pick one; plain numbers run
in sequence.

### iOS track

| Step                          | Condition                              | Read                                                                       |
|-------------------------------|----------------------------------------|----------------------------------------------------------------------------|
| 1. Scan                       | always (first, after intake)           | [`ios/stages/1-scan.md`](ios/stages/1-scan.md)                             |
| 2A. Install — CocoaPods       | CocoaPods chosen (per Step 1)          | [`ios/stages/2a-install-cocoapods.md`](ios/stages/2a-install-cocoapods.md) |
| 2B. Install — SPM             | SPM chosen (per Step 1; the default)   | [`ios/stages/2b-install-spm.md`](ios/stages/2b-install-spm.md)             |
| 3. Permissions & capabilities | always                                 | [`ios/stages/3-permissions.md`](ios/stages/3-permissions.md)               |
| 4. Integration file           | always                                 | [`ios/stages/4-integration-code.md`](ios/stages/4-integration-code.md)     |
| 5. Wire into target           | always (right after creating the file) | [`ios/stages/5-wire-target.md`](ios/stages/5-wire-target.md)               |
| 6A. Launch — UIKit            | host is a UIKit ViewController         | [`ios/stages/6a-launch-uikit.md`](ios/stages/6a-launch-uikit.md)           |
| 6B. Launch — SwiftUI          | host is a SwiftUI view                 | [`ios/stages/6b-launch-swiftui.md`](ios/stages/6b-launch-swiftui.md)       |

### Android track

| Step                      | Condition                                                | Read                                                                                   |
|---------------------------|----------------------------------------------------------|----------------------------------------------------------------------------------------|
| 1. Scan                   | always (first, after intake)                             | [`android/stages/1-scan.md`](android/stages/1-scan.md)                                 |
| 2. Install — Dependencies | always                                                   | [`android/stages/2-install-dependencies.md`](android/stages/2-install-dependencies.md) |
| 3. Integration file       | always (Gradle auto-compiles — no wire-into-target step) | [`android/stages/3-integration-code.md`](android/stages/3-integration-code.md)         |
| 4. Launch                 | always                                                   | [`android/stages/4-launch.md`](android/stages/4-launch.md)                             |

> **Fallback (last resort only).** This skill and its branch files are the primary
> source — don't reach for external docs by default. Only if you hit a genuine blocker
> they don't resolve, consult the Sumsub docs:
> [iOS](https://docs.sumsub.com/docs/get-started-ios) ·
> [Android](https://docs.sumsub.com/docs/get-started-android).

When the tree is walked, return here for **Guardrails** and **Handoff**.

## Guardrails — what this skill must never do

- **Detect the platform first** — never emit Swift into an Android project or Kotlin into an iOS one; if both are
  present, ask which to integrate.
- **Never edit existing app code** beyond the single targeted call site the user approved in intake.
- **(iOS) Let the SDK present itself — in SwiftUI too.** Always launch via `SumsubVerification.start()` (
  `sdk.present()` / `sdk.present(from:)`). **Never** strong-hold the SDK or its `mainVC` across the flow, and **never**
  bridge `sdk.mainVC` into a SwiftUI `.fullScreenCover` / `.sheet`. `mainVC` strong-retains the SDK and the SDK fires
  `onDidDismiss` from that controller's `dealloc`; holding it yourself delays teardown and causes "opens every other
  time" + a crash on re-open. The SDK owns presentation **and** dismissal — one owner, clean re-open.
- **(Android) Never add camera/mic permissions or runtime prompts** — the SDK declares and requests them itself; adding
  your own can double-prompt or conflict.
- **(Android) The token-refresh handler is synchronous** — `onTokenExpired()` must return the token on a background
  thread; bridge the suspend token call with `runBlocking`, not the iOS async/callback pattern.
- **Never run a project-mutating command** (`pod install`, a Gradle sync/build) without explicit user permission in the
  current message.
- **Never ask for or reference the App Token or secret key** — tokens are minted server-side.
- **Never store or reference the App Token or secret key** in any app file.
- **Never silently overwrite** an existing Info.plist / AndroidManifest value — always show the current value and ask
  first.
- **Never apply theme changes** in this skill — styling belongs in `sumsub-theme-msdk`.
- **Never gate access on in-app callbacks** — the authoritative verdict comes from the backend (webhook + applicant
  GET), not the SDK callbacks.

## Handoff

After all changes are complete, summarise clearly:

1. **Files created / modified** — list each with a one-line description.
2. **Stub that needs filling in** — if the token fetch is a placeholder, say so explicitly and describe what the user
   must implement. (On Android it's the single `SumsubTokenProvider.fetchAccessToken` suspend function — the launcher
   reuses it for mid-session refresh.)
3. **Build step** — iOS: "Run `pod install`, then open the `.xcworkspace` and build" or "Build and run — SPM packages
   resolve automatically"; Android: "Sync Gradle, then build & run".
4. **How to test** — explain: get a sandbox access token from your backend (or temporarily hardcode one), trigger
   verification from the launch point (iOS: `SumsubVerification.start(…)`; Android: the ViewModel action whose effect
   makes the screen call `SumsubLauncher.present(…)`), and verify the Sumsub flow appears. (NFC modules need a
   physical device — not the iOS simulator / Android emulator.)
5. **Source of truth** — remind the user: the final verification result comes from the backend webhook + applicant read,
   not from the SDK callbacks.
6. **Next steps** — point to `sumsub-theme-msdk` for styling (iOS & Android).

