> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chmodlab.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Document capture

> Detection mode, automatic or manual capture, photo preview and retake limits.

How the SDK captures the document: whether it detects the type itself or asks the user,
whether it shoots automatically, and how many times it lets the user try again.

<CodeGroup>
  ```swift iOS lines theme={null}
  let documentCapture = ChmodKycConfiguration.DocumentCapture(
      detectionMode:       .auto,  // .auto .userSelect .userSelectStrict .autoAndHideDocumentOptions
      captureMode:         .auto,  // .auto .manual
      showsPhotoPreview:   true,   // Lets the user confirm the photo before it is uploaded
      maxRetakesOnFailure: 3       // Retries allowed before the flow fails
  )
  ```

  ```kotlin Android lines theme={null}
  val documentCapture = SdkConfig.DocumentCapture(
      documentTypeDetectionMode = DocumentTypeDetectionMode.AUTO,  // AUTO, USER_SELECT, USER_SELECT_STRICT, AUTO_AND_HIDE_DOCUMENT_OPTIONS
      documentPhotoCaptureMode  = DocumentPhotoCaptureMode.AUTO,   // AUTO, MANUAL
      showPhotoPreview          = true,                            // Lets the user confirm the photo before it is uploaded
      maxPhotoRetakeOnFailed    = 3                                // Retries allowed before the flow fails
  )
  ```
</CodeGroup>

## Detection mode

Who decides what document is being photographed.

| Mode | Behaviour |
| - | - |
| `AUTO` | The SDK identifies the type and country from the image. Default. |
| `USER_SELECT` | The user picks type and country first; the SDK still detects and can disagree |
| `USER_SELECT_STRICT` | The user picks, and only that exact type is accepted |
| `AUTO_AND_HIDE_DOCUMENT_OPTIONS` | Fully automatic, with no type selector shown at all |

`AUTO` is right for most integrations: it is one less screen, and the SDK is better at
reading a document than a user is at classifying their own.

<Info>
  `USER_SELECT` is worth it when your users routinely carry several accepted documents and
  you want to steer them, or when your support team needs to know what the user *believed*
  they were photographing. That intent comes back as a `DOCUMENT_TYPE_MISMATCH` warning
  when it disagrees with what was actually extracted.
</Info>

`USER_SELECT_STRICT` is the strictest and the most fragile: a user who picks the wrong option fails a document that would otherwise have been fine. Reach for it only when you genuinely need to force one specific document, and remember that [`document_eligibility`](/configuration/document-policy) already enforces that server-side — where the user cannot get it wrong.

## Capture mode

| Mode | Behaviour |
| - | - |
| `AUTO` | Shoots automatically once the document is aligned, sharp and well lit. Default. |
| `MANUAL` | The user presses a shutter button |

`AUTO` produces markedly better images, because the SDK only fires when its own quality
checks pass. `MANUAL` mostly exists for users who struggle with automatic capture — an
unsteady hand, an unusual document, difficult lighting.

## Photo preview

<ParamField body="showsPhotoPreview / showPhotoPreview" type="boolean" default="true">
  Shows the captured photo and lets the user confirm or retake before it is uploaded.
</ParamField>

Keep it on. A user who can see a blurred photo will retake it themselves, which is far
cheaper than a rejection several seconds later with a `DOCUMENT_IMAGE_UNUSABLE` issue that
you then have to explain.

## Retakes

<ParamField body="maxRetakesOnFailure / maxPhotoRetakeOnFailed" type="integer" default="3">
  How many times capture may fail before the flow ends. `0` disables retakes entirely.
</ParamField>

When the limit is hit, the flow ends with `documentScanMaxRetries` on iOS or
`DOCUMENT_SCAN_MAX_RETRIES` on Android.

Three is a reasonable balance. Raising it much higher rarely converts — a user who has
failed five times usually has a damaged document or a broken camera, and the useful
response is human support, not a sixth attempt.

<Warning>
  `0` looks strict but is usually the wrong choice: it fails a user for a single unlucky frame. Server-side rules in the [transaction configuration](/configuration/overview) are where strictness belongs, since the app cannot weaken them.
</Warning>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.