📘

This guide is specific to Web SDK 2.0. If you are still using 1.x, you can find documentation [here](https://developer.incode.com/docs/web-sdk-reference). Contact your Incode Representative for upgrade information and check if you are a candidate for this upgrade.

Full rollout to all clients still TBD.

The ID Capture module captures front and back images of identity documents (ID cards, passports) with ML-powered quality checks and validation.

Follows the [camera-capture pattern](https://developer.incode.com/docs/web-sdk-2-module-patterns#2-camera-capture-modules), plus dedicated states for mandatory consent and manual file upload. See the patterns page for the shared lifecycle; the rest of this page covers ID-specific config, capture properties, and methods.

## Tag   
`<incode-id>` is a standard Web Component. Importing the UI subpath registers the custom element; importing the CSS applies the module's styles.

```ts
import '@incodetech/web/id';
import '@incodetech/web/id/styles.css';
```

## Properties   
Set these as JavaScript properties on the element (not as HTML attributes):

| Property | Type | Required | Description |
| --- | --- | --- | --- |
| `config` | `IdCaptureConfig` | ❌ | Configuration for ID capture behavior |
| `manager` | `IdCaptureManager` | ❌ | Optional pre-built manager (advanced use) |
| `onFinish` | `() => void` | ❌ | Called when capture completes successfully |
| `onError` | `(error: string | undefined) => void` | ❌ | Called when an error occurs |

## WASM Requirements   
The ID Capture module uses WebAssembly for document detection, blur/glare quality checks, and perspective correction. Pre-warm WASM during `setup()` so models are ready before the user reaches the camera step:

```typescript
await setup({
  apiURL: 'https://demo-api.incodesmile.com',
  token: 'your-session-token',
  wasm: { pipelines: ['idCapture'] },
});
```

See [WASM Configuration](https://developer.incode.com/docs/web-sdk-2-wasm) for self-hosted paths and the lower-level `warmupWasm()` API.

## Usage   
### Vanilla HTML / TypeScript   
HTML

```html
<incode-id></incode-id>

<script type="module">
  import { setup } from '@incodetech/core';
  import '@incodetech/web/id';
  import '@incodetech/web/id/styles.css';

await setup({
    apiURL: 'https://demo-api.incodesmile.com',
    token: 'your-session-token',
    wasm: { pipelines: ['idCapture'] },
  });

const id = document.querySelector('incode-id');
  id.config = {
    showTutorial: true,
    enableId: true,
    enablePassport: false,
    autoCaptureTimeout: 5,
    captureAttempts: 3,
  };
  id.onFinish = () => console.log('ID captured!');
  id.onError = (err) => console.error('ID error:', err);
</script>
```

### React   
```tsx
import { useEffect, useRef } from 'react';
import { setup } from '@incodetech/core';
import type { IdCaptureConfig } from '@incodetech/core/id';
import '@incodetech/web/id';
import '@incodetech/web/id/styles.css';

type IdElement = HTMLElement & {
  config: IdCaptureConfig;
  onFinish: () => void;
  onError: (error: string | undefined) => void;
};

await setup({
  apiURL: 'https://demo-api.incodesmile.com',
  token: 'your-session-token',
  wasm: { pipelines: ['idCapture'] },
});

export function IdCapture() {
  const ref = useRef<IdElement>(null);

useEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.config = {
      showTutorial: true,
      enableId: true,
      enablePassport: false,
      autoCaptureTimeout: 5,
      captureAttempts: 3,
    };
    el.onFinish = () => console.log('ID captured!');
    el.onError = (err) => console.error('ID error:', err);
  }, []);

return <incode-id ref={ref} />;
}
```

### Workflow vs Flow   
In a dashboard-driven Flow (`<incode-flow>` / `createOrchestratedFlowManager`), `ID` is a single step that captures the document **and** runs server-side processing (`/process/id`). This is what `<incode-id>` and `createIdCaptureManager` do by default.

In a server-driven Workflow (`<incode-workflow>` / `createWorkflowManager`), the workflow engine emits ID handling as **two distinct nodes**:

1. `ID_CAPTURE` — runs `idCaptureMachine` for the capture portion only, then advances without calling `/process/id`. Enabled by setting `IdCaptureConfig.skipProcessId = true` (the workflow engine sets this automatically on the `ID_CAPTURE` node's config).
2. `ID` — runs the headless `id-verification` module (`@incodetech/core/id-verification`, `createIdVerificationManager`) which invokes `/process/id` on its own. The orchestrator renders the corresponding `<incode-id-verification>` shell while the request is in flight. No UI work needed.

This split lets the workflow inject custom logic (manual review, retries, branching) between capture and verification. For a single-step capture+verify flow, keep using the standard `<incode-id>` / `createIdCaptureManager` path — `skipProcessId` defaults to `false`, so processing runs inline as before.

### API Methods   
| Method | Description | When to Use |
| --- | --- | --- |
| `load()` | Starts the ID capture flow | Always call first |
| `selectDocument(type)` | Selects `'id'` or `'passport'` | When `chooser` |
| `capture()` | Manual capture trigger | When `detectionStatus === 'manualCapture'` |
| `close()` | Close the flow | Anytime |
| `getState()` | Returns current state | Anytime |
| `subscribe(callback)` | Subscribe to state changes | Returns unsubscribe function |

### Detection Status Values   
| Status | User Instruction |
| --- | --- |
| `idle` | "Preparing camera..." |
| `detecting` | "Hold steady..." |
| `offline` | "No network connection" |

### Error Codes   
| Code | Description | User Action |
| --- | --- | --- |
| `UPLOAD_ERROR` | Upload failed | Retry capture |
| `CLASSIFICATION_FAILED` | Document not recognized | Use clearer image |
| `LOW_SHARPNESS` | Image too blurry | Hold device steadier |
| `NO_TOKEN` | Session token missing | Re-initialize SDK |

## Examples   
### ID Card Only   
```ts
const config: IdCaptureConfig = {
  enableId: true,
  enablePassport: false,
  showTutorial: true,
  autoCaptureTimeout: 5,
};
```

### Passport Only   
```ts
const config: IdCaptureConfig = {
  enableId: false,
  enablePassport: true,
  showTutorial: false,
};
```

### Capture-only flow   
`createIdCaptureOnlyManager` exposes the same state machine and API surface as `createIdCaptureManager`, but bypasses the Incode upload pipeline. Instead of submitting the captured frames to Incode and waiting on server-side processing, the manager invokes a customer-supplied `onCapture(response)` callback with the captured images and reaches `finished` locally.
