> For the complete documentation index, see [llms.txt](https://docs.caf.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.caf.io/caf-sdk/ios/getting-started-with-the-sdk-2.md).

# Document Detector

{% hint style="warning" %}

## This guide covers version 7.0.0 and above. For versions below 7.0.0, please see the [legacy documentation](/caf-sdk/ios/getting-started-with-the-sdk-5.md).

{% endhint %}

## Overview

**Document Detector for iOS** guides the user through capture and validation of identity documents (RG, CNH, passport, etc.). With **Certta**, you run it on the same session as Face Liveness and Smart Capture: configure credentials once, then open the native flow with **`CerttaDocumentDetector`**.

This guide covers prerequisites, **Certta** session requirements, **`CerttaDocumentDetectorConfiguration`** (including **`CerttaDocumentDetectorUIConfiguration`**), **`open`** / **`loadSession`**, results on **`CerttaDocumentDetectorDelegate`**, cancel and logs on **`CerttaDelegate`**, and theming.

{% content-ref url="/pages/QVmGfrLJMR8O4Q5XW3Vm" %}
[Installation Guide](/caf-sdk/ios/getting-started-with-the-sdk.md)
{% endcontent-ref %}

{% content-ref url="/pages/6acuvNOcVXBaHqI0Hg7O" %}
[Customizing Document Detector](/caf-sdk/ios/getting-started-with-the-sdk-2/customizing-document-detector.md)
{% endcontent-ref %}

***

### Mapping events and results

**`CerttaDocumentDetectorDelegate`** is intentionally small: **success** and **blocking errors** only.

| Callback                                  | Purpose                                                                                                                   |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **`didFinish(result:)`**                  | Successful end of the flow. **`result`** is the signed payload / JWT string from CAF (treat as sensitive).                |
| **`didFinishWith(_ error: CerttaError)`** | Session invalid, camera/network/security/initialization issues, and **unified pipeline processing failures** (see below). |

{% hint style="warning" %}
Ensure the JWT response is evaluated on the backend. This process must include validating the token's signature and verifying the `isAlive` and `isMatch` fields. Do not perform these validations on the client side.
{% endhint %}

**What moved to `CerttaDelegate`**

* **User cancel** → **`certtaDidCancel()`** on **`Certta.shared.delegate`** (not on **`CerttaDocumentDetectorDelegate`**).
* **Pipeline logs** (levels/messages) → **`certtaDidLog(level:message:)`** on **`CerttaDelegate`**.
* **`.loading` / `.loaded`** from the unified pipeline are **not** forwarded to **`CerttaDocumentDetectorDelegate`** (use **`loadSession`** for warm-up only).

**Processing failures (`CafUnifiedEvent.failure`)**

* There is **no** separate **`didFail(_: CerttaDocumentDetectorFailure)`** on **`CerttaDocumentDetectorDelegate`**.
* Failures are **logged** by the SDK and surfaced to **`didFinishWith`** as **`CerttaError.unknownError(String)`**, where the string includes result/cause context when available.

**Migration from older samples**

* Replace **`didFinish(signedResponse:)`** with **`didFinish(result:)`** (same string semantics).
* Implement **`CerttaDelegate`** if you previously handled cancel or logs on the Document Detector delegate.

***

## Prerequisites

1. **CAF SDK** installed — **installation guide** (Swift Package Manager or CocoaPods).
2. **DocumentDetector** linked with **CafSDK**, per your distribution (SPM / CocoaPods / XCFramework).
3. **Info.plist** — camera usage (required):

```xml
<key>NSCameraUsageDescription</key>
<string>We need the camera to capture your document.</string>
```

4. **Photo library** — add **`NSPhotoLibraryUsageDescription`** only if your product lets users pick images from the library.
5. **Active Certta session** — call **`Certta.shared.configure(configuration:)`** so **mobile token** and **user ID** are non-empty **before** **`open`**. Missing session or credentials surface **`CerttaError`** (typically **`initializationError`**) via **`didFinishWith`**.

***

## Start Document Detector

Use **`CerttaDocumentDetector.shared`**. Set **`delegate`**, **or** conform the presenting **`UIViewController`** to **`CerttaDocumentDetectorDelegate`** — resolution order: **`delegate ?? (presenter as? CerttaDocumentDetectorDelegate)`**.

#### Minimal configuration (legacy-style initializer)

Only **`flow`** is required for a real session. Other parameters use defaults on **`init(flow:layout:uploadSettings:instructionsConfig:requestTimeout:showPreCapturePopup:showPreview:ddCustomizations:enableMultiLanguage:selectDocumentConfig:maxRetryAttempts:)`**.

```swift
CerttaDocumentDetector.shared.open(
    from: self,
    configuration: CerttaDocumentDetectorConfiguration(
        flow: [
            CafDocumentDetectorStep(stepType: .rgFront),
            CafDocumentDetectorStep(stepType: .rgBack)
        ],
        maxRetryAttempts: 3
    )
)
```

Avoid shipping **`CerttaDocumentDetectorConfiguration(flow: [])`** with an empty flow.

### Recommended: **`CerttaDocumentDetectorUIConfiguration`**

Use **`CerttaDocumentDetectorConfiguration.init(flow:ui:enableMultiLanguage:)`**. **`flow`** stays on **`CerttaDocumentDetectorConfiguration`**. Copy, capture styling (**`captureScreen`**), upload, timeouts, preview, popup, retries, and **`[CafDDCustomization]`** live on **`CerttaDocumentDetectorUIConfiguration`**, aligned with Android’s **`DocumentDetectorUiConfiguration`**. Internally these map to **`CafDocumentDetectorLayout`**, capture-related **`CafInstructionsConfiguration`**, and **`CafSelectDocumentConfig`**.

```swift
let ui = CerttaDocumentDetectorUIConfiguration()
ui.documentSelectionScreen.title = "Choose document type"
ui.instructionsScreen.title = "Scan your document"
ui.instructionsScreen.message = "Align the card inside the frame"
ui.maxRetryAttempts = 3

CerttaDocumentDetector.shared.open(
    from: self,
    configuration: CerttaDocumentDetectorConfiguration(
        flow: [
            CafDocumentDetectorStep(stepType: .rgFront),
            CafDocumentDetectorStep(stepType: .rgBack)
        ],
        ui: ui
    )
)
```

* **`ui: CerttaDocumentDetectorUIConfiguration()`** — SDK defaults for all UI fields.
* **`layoutResourceName`** — optional; reserved for future native layout hooks, **unused** by the default UI (similar intent to Android **`layoutId`**).

The legacy initializer **`init(flow:layout:uploadSettings:instructionsConfig:…)`** remains available if you assemble **`CafDocumentDetectorLayout`**, **`CafInstructionsConfiguration`**, and **`CafSelectDocumentConfig`** yourself.

You can also bridge an existing UI bundle with **`CerttaDocumentDetectorUIConfiguration.init(layout:instructions:documentTypeSelection:)`**.

### `loadSession`

Call **`CerttaDocumentDetector.shared.loadSession(from:configuration:)`** before **`open`** with the **same** **`CerttaDocumentDetectorConfiguration`** to warm caches and resources. **`.loading` / `.loaded`** are **not** delivered to **`CerttaDocumentDetectorDelegate`**.

***

#### `CerttaDocumentDetectorConfiguration` parameters

| Initializer                                                 | When                                                                      |
| ----------------------------------------------------------- | ------------------------------------------------------------------------- |
| **`init(flow:ui:enableMultiLanguage:)`**                    | **Recommended** — structured **`CerttaDocumentDetectorUIConfiguration`**. |
| **`init(flow:layout:uploadSettings:instructionsConfig:…)`** | Raw **`Caf*`** types without the unified UI struct.                       |
| **`init(from: CafDocumentDetectorConfig)`**                 | You already have a full **`CafDocumentDetectorConfig`** (e.g. migration). |

On the **UI** path, timeouts, upload, preview, popup, retries, and customizations come from **`CerttaDocumentDetectorUIConfiguration`**. On the **legacy** path, override per-field defaults on the long **`init`**.

| Field                                   | Notes                                                                                                                                   |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **`flow`**                              | **`[CafDocumentDetectorStep]`** — required for a real session.                                                                          |
| **`layout`**                            | Legacy only. UI path: built from **`captureScreen`** → **`CafDocumentDetectorLayout`**.                                                 |
| **`uploadSettings`**                    | Legacy defaults vs UI path (**`CerttaDocumentDetectorUIConfiguration.uploadSettings`**, default upload **disabled** / Android-aligned). |
| **`instructionsConfig`**                | Legacy. UI path: from **`instructionsScreen`**.                                                                                         |
| **`requestTimeout`**                    | Legacy: **`TimeInterval`**. UI path: **`Int`** seconds on **`CerttaDocumentDetectorUIConfiguration`**, default **60**.                  |
| **`showPreCapturePopup` / `showPopup`** | UI path: **`showPopup`**, default **true**.                                                                                             |
| **`showPreview`**                       | UI path default **true** (Android-aligned); legacy default **false** on the long init.                                                  |
| **`ddCustomizations`**                  | UI path: **`customization.ddCustomizations`**.                                                                                          |
| **`enableMultiLanguage`**               | Default **true**; can be set on **`init(flow:ui:enableMultiLanguage:)`**.                                                               |
| **`selectDocumentConfig`**              | UI path: derived from **`documentSelectionScreen`** when titles/subtitles/custom maps are set.                                          |
| **`maxRetryAttempts`**                  | UI path: **`CerttaDocumentDetectorUIConfiguration.maxRetryAttempts`**, default **2**.                                                   |

#### Hub mapping and fixed defaults

**`init(from:)`** and the UI/legacy inits still map to **`CafDocumentDetectorConfig`** with **fixed** values for fields the Certta type does not expose:

| Field                                            | Hub behavior                             |
| ------------------------------------------------ | ---------------------------------------- |
| **`proxySettings`**                              | **`nil`** (not set via Certta)           |
| **`getUrlExpireTime`**                           | **`nil`**                                |
| **`currentStepDoneDelay`**                       | **1** (seconds)                          |
| **`allowedPassportCountryList`**                 | **`nil`**                                |
| **`manualCaptureEnabled` / `manualCaptureTime`** | **`true` / `0`** in the internal mapping |

For **full** control (proxy, expiry string, step delay, passport list, manual capture tuning), use **`CafSDKProvider.Builder`** with **`CafDocumentDetectorConfig`** — see the **configuration reference**.

### Supported Documents

| Document     | Description                                                                                                     |
| ------------ | --------------------------------------------------------------------------------------------------------------- |
| `RG_FRONT`   | Front side of the RG document, where the photo is located.                                                      |
| `RG_BACK`    | Back side of the RG document.                                                                                   |
| `RG_FULL`    | Open RG document, displaying both the front and back sides together.                                            |
| `CNH_FRONT`  | Front side of the CNH document, where the photo is located.                                                     |
| `CNH_BACK`   | Back side of the CNH document.                                                                                  |
| `CNH_FULL`   | Open CNH document, displaying both the front and back sides together.                                           |
| `CRLV`       | CRLV document.                                                                                                  |
| `RNE_FRONT`  | Front side of the RNE or RNM document.                                                                          |
| `RNE_BACK`   | Back side of the RNE or RNM document.                                                                           |
| `PASSPORT`   | Passport document, displaying the photo and personal data.                                                      |
| `CTPS_FRONT` | Front side of the CTPS document, where the photo is located.                                                    |
| `CTPS_BACK`  | Back side of the CTPS document.                                                                                 |
| `ANY`        | Allows submission of any type of document, including all those listed above or any other unclassified document. |

## Understanding Document Detector Events & Results

***

### Events and results

#### `CerttaDocumentDetectorDelegate`

```swift
extension MyViewController: CerttaDocumentDetectorDelegate {

    func didFinish(result: String) {
        // Success — signed payload from Document Detector; validate on your backend per CAF docs.
    }

    func didFinishWith(_ error: CerttaError) {
        switch error {
        case .initializationError(let message): break
        case .permissionError(let message): break
        case .securityError(let message): break
        case .unknownError(let message): break   // includes unified .failure pipeline context
        case .networkError(let message): break
        }
    }
}
```

**`CerttaError`** exposes **`message`** and conforms to **`LocalizedError`** (**`errorDescription`**).

* **`didFinish(result:)`** — Do **not** log the full token in production.
* **`didFinishWith`** — Invalid session, permissions, network, security, initialization, and **processing failures** (as **`unknownError`**).

#### `CerttaDelegate` (cancel & logs)

```swift
extension MyViewController: CerttaDelegate {

    func certtaDidCancel() {
        // User dismissed the flow — Document Detector, Face Liveness, or Smart Capture
    }

    func certtaDidLog(level: String, message: String) {
        // Optional diagnostics
    }
}
```

Set **`Certta.shared.delegate`** when you need cancel or log lines. Protocol methods have default empty implementations.

***

### Permissions and UX

* Request **camera** early when possible; otherwise expect **`permissionError`** via **`didFinishWith`**.
* Use clear copy on **`instructionsScreen`** / selection so users know how to align the document.
* On **cancel**, handle **`certtaDidCancel()`** with predictable navigation (back or retry).

***

### Colors and theming

Pass **`CafColorConfiguration`** when you call **`Certta.shared.configure(configuration:)`**, or update the active session with **`Certta.shared.setColorConfiguration(_:)`** (no-op if there is no session — call **`configure`** first). Document Detector consumes the same global palette as other Certta modules.

For **light vs dark** palettes, resolve hex strings from **`UITraitCollection.current.userInterfaceStyle`** (or your app theme) before building **`CafColorConfiguration`**.

Example (single dark-friendly palette using default SDK greens — adjust for your app):

```swift
Certta.shared.setColorConfiguration(
    CafColorConfiguration(
        primaryColor: "#34D690",
        secondaryColor: "#012D1F",
        contentColor: "#CDCDCD",
        backgroundColor: "#000000",
        mediumColor: "#D1D1D1",
        dialogBackgroundColor: "#1C1C1E",
        dialogBorderColor: "#E5E5E7"
    )
)
```

***

### Legacy **`CafSDKProvider`**

If you do **not** use the Certta hub for Document Detector, integrate with **`CafSDKProvider.Builder`** and a full **`CafDocumentDetectorConfig`** for proxy, URL expiry, delays, passport list, and manual capture — see **configuration reference**.

***

### Release notes

See **Changelog** / **GitHub Releases** for versions, breaking changes, and minimum **Xcode** / **iOS**.

***

### Support

Use your **CAF / Certta** support channel, **FAQ**, and **repository** for issues and updates.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.caf.io/caf-sdk/ios/getting-started-with-the-sdk-2.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
