> For the complete documentation index, see [llms.txt](https://legacy-docs.usesmileid.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://legacy-docs.usesmileid.com/integration-options/web-mobile-web/web-integration/usage.md).

# Usage

## Steps

1. Fetch the web token from your server, when ready
2. Configure the web integration
3. Test the Integration

### Fetch the Web Token from your server

Using the Web Token endpoint set up on your server, fetch a web token for the client

This can take the form of a click event on your web site or application.

```javascript
const baseAPIURL = `${your - API - server - URL}`;

const getWebToken = async (baseAPIURL) => {
  const fetchConfig = {};

  fetchConfig.cache = "no-cache";
  fetchConfig.mode = "cors";
  fetchConfig.headers = {
    Accept: "application/json",
    "Content-Type": "application/json",
  };
  fetchConfig.method = "POST";

  const URL = `${baseAPIURL}/token/`;
  try {
    const response = await fetch(URL, fetchConfig);

    if (response.status === 200 || response.statusCode === 200) {
      const json = await response.json();

      if (json.error) {
        throw new Error(json.error);
      }

      return json;
    }
  } catch (e) {
    console.log(`API: ${e.name}, ${e.message}`);
    throw e;
  }
};

const verifyWithSmileIdentityButton = document.querySelector(
  "#verify-with-smile-id",
);

verifyWithSmileIdentityButton.addEventListener(
  "click",
  async (e) => {
    e.preventDefault();

    verifyWithSmileIdentityButton.textContent = "Initializing session...";
    verifyWithSmileIdentityButton.disabled = true;

    const { token } = await getWebToken(baseAPIURL);
  },
  false,
);
```

### Configure the Web Integration

With the web token, we can now configure our integration

<pre class="language-javascript"><code class="lang-javascript">const configureSmileIdentityWebIntegration = (token) => {
  SmileIdentity({
    token,
    product: "biometric_kyc",
    callback_url: `${your - API - server - URL}/callback`,
    environment: "sandbox",
    use_strict_mode: true,
    partner_details: {
      partner_id: `${your - smile - identity - partner - id}`,
      name: `${your - app - name}`,
      logo_url: `${your - app - logo - url}`,
      policy_url: `${your - data - privacy - policy - url}`,
      theme_color: "#000",
    },
    partner_params:{
        "sample_meta_data": "meta-data-value", //include meta data
<strong>        "sandbox_result" : "0" //mock sandbox result
</strong>    }, 
    onSuccess: () => {},
    onClose: () => {},
    onError: () => {},
  });
};

// ACTION: call the initialization function in the event handler
verifyWithSmileIdentityButton.addEventListener(
  "click",
  async (e) => {
    e.preventDefault();

    verifyWithSmileIdentityButton.textContent = "Initializing session...";
    verifyWithSmileIdentityButton.disabled = true;

    try {
      const { token } = await getWebToken(baseAPIURL);
      configureSmileIdentityWebIntegration(token);
    } catch (e) {
      throw e;
    }
  },
  false,
);
</code></pre>

The API for configuring the integration is as follows

<table><thead><tr><th width="222.7142857142857">Key</th><th width="117">Type</th><th width="168">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>token</code></td><td>string</td><td>Yes</td><td>token generated on the server side using the <code>get_web_token</code> method in one of our server-to-server libraries<br></td></tr><tr><td><code>product</code></td><td>string</td><td>Yes</td><td><p>one of the Smile ID products.<br><br><code>"biometric_kyc"</code> <code>"doc_verification</code><br><code>"authentication"</code><br><code>"basic_kyc"</code><br><code>"smartselfie"</code><br><code>"enhanced_kyc"</code><br><code>"enhanced_document_verification"</code></p><p><code>"e_signature"</code></p></td></tr><tr><td><code>document_ids</code></td><td>array</td><td>Yes (for <code>e_signature</code>)</td><td>a list of previously uploaded document IDs<br></td></tr><tr><td><code>callback_url</code></td><td>string</td><td>Yes</td><td>a callback URL on your API server or wherever you prefer.</td></tr><tr><td><code>environment</code></td><td>string</td><td>Yes</td><td>one of <code>"sandbox"</code> or <code>"live"</code></td></tr><tr><td><code>partner_details</code></td><td>object</td><td>Yes</td><td>customizations for your organization. details <a href="#undefined">here</a></td></tr><tr><td><code>partner_params</code></td><td>object</td><td>No</td><td>a collection of partner additional information. All its contents are sent back to the partner but in a slightly different format. The objects key name is changed to <strong><code>PartnerParams</code></strong>. It can be used to hold meta data related to the user or the job.<br><br>Additionally, if you intend to <a href="/pages/2hvprIvnS9XbKizdeOJv#mocking-results-in-sandbox-environment">mock the sandbox results</a>, you should include the include the <code>sandbox_result</code> key as <a href="/pages/2hvprIvnS9XbKizdeOJv#how-to-mock-results">string value "0", "1" or "2"</a></td></tr><tr><td><code>onSuccess</code></td><td>function</td><td>No</td><td>function to handle successful completion of the verification.</td></tr><tr><td><code>onError</code>*</td><td>function</td><td>No</td><td>function to handle errors with verification, called when end-user consent is denied</td></tr><tr><td><code>onClose</code></td><td>function</td><td>No</td><td>function to handle closing of the verification process</td></tr><tr><td><code>id_selection</code>**</td><td>object</td><td>No</td><td><p>a mapping of country code to a selection of <a href="https://docs.usesmileid.com/supported-id-types/for-individuals-kyc/backed-by-id-authority">supported id types</a> e.g.</p><p><code>{</code></p><p><code>"NG": ["BVN_MFA", "V_NIN"]</code></p><p><code>}</code></p></td></tr><tr><td><code>consent_required</code> ***</td><td>object</td><td>Yes, for ID Types where user consent is required.</td><td><p>a mapping of country code to a selection of <a href="https://docs.usesmileid.com/supported-id-types/for-individuals-kyc/backed-by-id-authority">supported id types</a> e.g.</p><p><code>{</code></p><p><code>"NG": ["BVN", "NIN"]</code></p><p><code>}</code></p></td></tr><tr><td><code>document_capture_modes</code></td><td>array</td><td>No</td><td><p>a list containing <code>camera</code> or <code>upload</code> or <em><strong>both values</strong></em> if you intend to provide both options for document image acquisition.</p><p><code>{</code></p><p><code>"document_capture_modes":["camera","upload"]</code></p><p><code>}</code><br><br>if you do not provide the <code>document_capture_modes</code> list, the component defaults to the <code>camera</code> option.</p></td></tr><tr><td><code>auto_capture_enabled</code></td><td>boolean</td><td>No</td><td><p>Master switch for the new document auto-capture engine. Defaults to <code>false</code> in the current major version; set to <code>true</code> to opt in early. <strong>The next major version will default this to <code>true</code>.</strong></p><p>When <code>false</code>, the <code>auto_capture</code> and <code>auto_capture_timeout</code> options have no effect. See <a href="#document-auto-capture">Document auto-capture</a>.</p></td></tr><tr><td><code>auto_capture</code></td><td>string</td><td>No</td><td><p>Controls the document capture mode. One of:</p><ul><li><code>"autoCapture"</code> (default): auto-capture with a manual-capture fallback after <code>auto_capture_timeout</code></li><li><code>"autoCaptureOnly"</code>: auto-capture only, with no manual fallback</li><li><code>"manualCaptureOnly"</code>: manual capture only</li></ul><p>We strongly recommend leaving this as <code>"autoCapture"</code>. See <a href="#document-auto-capture">Document auto-capture</a>.</p></td></tr><tr><td><code>auto_capture_timeout</code></td><td>number</td><td>No</td><td>Time in milliseconds before the manual-capture fallback button appears during auto-capture. Defaults to <code>10000</code> (10 seconds). Only applies when <code>auto_capture</code> is <code>"autoCapture"</code>. We advise not changing this unless you need to.</td></tr><tr><td><code>allow_agent_mode</code></td><td>boolean</td><td>No</td><td>Whether to allow Agent Mode or not. If allowed, a button will be displayed allowing toggling between the back camera and front camera. If not allowed, only the front camera will be used. To use agent mode, the new design should be opted for by setting <code>use_new_component: true</code></td></tr><tr><td><code>id_info</code>****</td><td>object</td><td>No</td><td>Pre-fill ID information fields (country, ID type, field values). When exactly 1 country and 1 ID type are provided, the selection screen is automatically skipped. When all required fields are valid, the input screen is also skipped. Valid pre-filled fields are locked (read-only). Takes precedence over <code>id_selection</code> when both are provided. See <a href="#id_info-configuration-reference">id_info configuration reference</a></td></tr></tbody></table>

\* - `onError` function can take one argument of the shape `{ message: <message>, data: <object with details> }`

\*\* - `id_selection` list is checked against those enabled for your partner account. this is limited in cases of `basic_kyc`, `enhanced_kyc`, `enhanced_document_verification`, and `biometric_kyc`.

{% hint style="info" %}
If you pass only one **country** and **id type** in the`id_selection` object, the id type selection screen will not be displayed in the web integration instance
{% endhint %}

\*\*\* - `consent_required` list is subject to the ID Authority configuration. Some ID Authorities require end-user consent, and that requirement overrides this setting.

\*\*\*\* - `id_info` takes precedence over `id_selection`. When using `id_info`, you can pre-fill country, ID type, and field values to streamline the user experience.

#### Enhanced SmartSelfie strict mode

Enable Enhanced SmartSelfie in hosted web integration by setting `use_strict_mode: true` at the top level of the SmileIdentity config object.

```javascript
SmileIdentity({
  token,
  product: "smartselfie",
  callback_url: `${your - API - server - URL}/callback`,
  use_strict_mode: true,
  allow_legacy_selfie_fallback: false,
  onSuccess: () => {},
  onClose: () => {},
  onError: () => {},
});
```

* `use_strict_mode: true` enables the strict-mode selfie flow.
* `allow_legacy_selfie_fallback: true` is optional. If enabled, the integration may fall back to the legacy selfie flow when MediaPipe cannot initialize.

#### Document auto-capture

The new document auto-capture engine captures document images automatically, ensuring documents are captured at the highest possible quality. During a document capture session, the integration continuously attempts auto-capture. If it cannot complete auto-capture within the `auto_capture_timeout` window (10 seconds by default), a manual-capture fallback button appears so the user can capture the document themselves.

In the current major version the new auto-capture is **opt-in**: enable it by setting `auto_capture_enabled: true`. **The next major version will enable it by default.** Once enabled, control the mode with the `auto_capture` option:

```javascript
SmileIdentity({
  token,
  product: "doc_verification",
  callback_url: `${your - API - server - URL}/callback`,
  environment: "sandbox",
  auto_capture_enabled: true,
  auto_capture: "autoCapture",
  auto_capture_timeout: 10000,
  partner_details: {
    partner_id: `${your - smile - identity - partner - id}`,
    name: `${your - app - name}`,
    logo_url: `${your - app - logo - url}`,
    policy_url: `${your - data - privacy - policy - url}`,
  },
  onSuccess: () => {},
  onClose: () => {},
  onError: () => {},
});
```

| `auto_capture` value  | Behaviour                         | Manual capture | Auto-capture | Pass-rate impact |
| --------------------- | --------------------------------- | -------------- | ------------ | ---------------- |
| `"autoCapture"`       | Auto-capture with manual fallback | ✅ fallback     | ✅            | Optimal          |
| `"autoCaptureOnly"`   | Auto-capture only                 | ❌              | ✅            | ⚠️ Possible drop |
| `"manualCaptureOnly"` | Manual capture only               | ✅              | ❌            | ⚠️ Possible drop |

{% hint style="warning" %}
We strongly advise leaving `auto_capture` set to `"autoCapture"`. Only switch to `"autoCaptureOnly"` or `"manualCaptureOnly"` if you have a specific reason to, and be aware of the performance differences between auto-capture and manual capture.
{% endhint %}

**Manual-capture fallback time**

Use `auto_capture_timeout` (in milliseconds) to extend or reduce how long the integration attempts auto-capture before showing the manual-capture button. The default is `10000` (10 seconds). We generally advise not changing this unless you absolutely need to.

{% hint style="info" %}
The `auto_capture` and `auto_capture_timeout` options only take effect when `auto_capture_enabled` is `true`. While `auto_capture_enabled` is `false` (the current default), the legacy capture behaviour is used and these options are ignored.
{% endhint %}

{% hint style="info" %}
Based on millions of usage data points, auto-captured documents have significantly higher pass rates than manually captured ones, because the auto-capture pipeline minimises blur and only captures once all quality checks pass. For more background on auto-capture performance and its limitations, see [Document auto-capture](/further-reading/faqs/document-autocapture.md).
{% endhint %}

**Migrating to the new auto-capture**

To adopt the new auto-capture engine ahead of the next major version, set `auto_capture_enabled: true` and test your document capture flow. When the next major version ships, `auto_capture_enabled` defaults to `true`, so no further action is needed to keep using auto-capture.

#### `id_info` configuration reference

Use `id_info` to pre-fill ID information and skip selection/input screens when all required data is provided. The structure is a nested object where top-level keys are country codes, each mapping to an object of ID types, which in turn map to field data.

**Basic example (single country + single ID type — skips selection screen):**

```javascript
SmileIdentity({
  token,
  product: "biometric_kyc",
  // ... other config
  id_info: {
    NG: {
      BVN: {
        id_number: "00000000000",
        first_name: "John",
        last_name: "Doe",
      },
    },
  },
});
```

**Multiple ID types (shows selection screen):**

```javascript
id_info: {
  NG: {
    BVN: { id_number: "00000000000" },
    NIN: { id_number: "98765432101" },
  },
}
```

**With `allow_modification` set to `false`:**

```javascript
id_info: {
  allow_modification: false,
  NG: {
    DRIVERS_LICENSE: {
      id_number: "ABC123456",
      first_name: "John",
      last_name: "Doe",
      dob: "1990-03-15",
    },
  },
}
```

**Structure:**

The `id_info` object has the following shape:

```
{
  allow_modification: boolean,   // optional, default: true
  <country_code>: {
    <id_type>: {
      id_number: string,
      first_name: string,
      last_name: string,
      dob: string,               // ISO format: 'YYYY-MM-DD'
      // ... any other fields required by the ID type
    }
  }
}
```

<table><thead><tr><th width="200">Key</th><th width="117">Type</th><th width="120">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>allow_modification</code></td><td>boolean</td><td>No</td><td><p>Controls validation behavior (top-level key):</p><ul><li><code>true</code> (default): Shows the input form when fields fail validation, allowing the user to correct them</li><li><code>false</code>: Skips the input screen when all fields are provided but some are invalid (e.g., regex mismatch); missing fields still require user input</li></ul></td></tr><tr><td><code>&#x3C;country_code></code></td><td>object</td><td>Yes</td><td>Two-letter country code (e.g., <code>"NG"</code>, <code>"KE"</code>, <code>"ZA"</code>). Maps to an object of ID types.</td></tr><tr><td><code>&#x3C;id_type></code></td><td>object</td><td>Yes</td><td>The ID type code (e.g., <code>"BVN"</code>, <code>"NATIONAL_ID"</code>, <code>"DRIVERS_LICENSE"</code>). Maps to an object of field values.</td></tr><tr><td><code>id_number</code></td><td>string</td><td>No</td><td>The ID number value (nested inside the ID type object)</td></tr><tr><td><code>dob</code></td><td>string</td><td>No</td><td>Date of birth in ISO format (<code>"YYYY-MM-DD"</code>). Automatically parsed into day/month/year fields.</td></tr><tr><td><em>Additional fields</em></td><td>string</td><td>No</td><td>Any additional fields required by the specific ID type (e.g., <code>first_name</code>, <code>last_name</code>), nested inside the ID type object</td></tr></tbody></table>

| `allow_modification` | Fields status               | Behavior                                                                       |
| -------------------- | --------------------------- | ------------------------------------------------------------------------------ |
| `true` (default)     | All valid                   | Skip input screen, submit                                                      |
| `true`               | Some invalid                | Show form with invalid fields editable                                         |
| `true`               | Some missing                | Show form with missing fields editable                                         |
| `false`              | All valid                   | Skip input screen, submit                                                      |
| `false`              | Some invalid (none missing) | Skip input screen, submit with data as-is (may result in verification failure) |
| `false`              | Some missing                | Show form with missing fields editable                                         |

{% hint style="info" %}
When `id_info` provides exactly 1 country and 1 ID type, the selection screen is automatically skipped. When all required fields are provided and valid, the input screen is also skipped. Valid pre-filled fields appear as read-only, while missing or invalid fields remain editable.
{% endhint %}

#### `partner_details` configuration reference

<table><thead><tr><th width="178.7142857142857">Key</th><th width="150">Type</th><th width="150">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>name</code></td><td>string</td><td>Yes</td><td>Application Name</td></tr><tr><td><code>partner_id</code></td><td>string</td><td>Yes</td><td>Smile ID Partner ID</td></tr><tr><td><code>policy_url</code></td><td>string</td><td>Yes</td><td>URL to data privacy policy</td></tr><tr><td><code>logo_url</code></td><td>string</td><td>Yes</td><td>URL to App Logo (best in 1:1 aspect ratio)</td></tr><tr><td><code>theme_color</code></td><td>string</td><td>No</td><td>a valid CSS Color Code for accent colors. When specified with the <code>use_new_component: true</code>, the color will be applied to header texts and buttons. Refer to <a href="#theme-color">theme color</a></td></tr></tbody></table>

### Test the Integration

After configuring the integration, you can walk through an example.

![](/files/RqqNwRGBkklGjEKRCnEM) ![](/files/Nqx5JtsyeuC2Lg6I28bk) ![](/files/BSCQpp2ksvWk1SuZ2n7B) ![](/files/SEPevTtBi49GEkEbCQKL) ![](/files/J30W29njn1Ksij4V0EBE) ![](/files/FBOm9O2HnVYB9OZ4ikCQ)

### Theme Color

![Color theming](/files/trFUJWISeRfmVsMjtk6o)

Please see the [trouble shooting guide here](/further-reading/troubleshooting/image-capture-issues-on-web-client.md#problem-camera-not-loading) for situations where the camera is not loading.


---

# 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://legacy-docs.usesmileid.com/integration-options/web-mobile-web/web-integration/usage.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.
