# Get started with WebSDK integration

Integrate with the Sumsub WebSDK.

To get started with the WebSDK integration:

1. [Generate an access token](https://docs.sumsub.com/sumsub/docs/get-started-with-web-sdk#generate-sdk-access-token) to be passed to the WebSDK during initialization.
2. [Install an NPM package](https://docs.sumsub.com/sumsub/docs/get-started-with-web-sdk#set-up-frontend-integration) or use the CDN version of the script. We also have a [package for React](https://docs.sumsub.com/sumsub/docs/get-started-with-web-sdk#react-integration).
3. Check if all the security headers and embedding requirements are complete.
4. Launch the WebSDK initialization function with the `accessToken` parameter you have generated at the first step, as shown in the [standalone example](https://docs.sumsub.com/sumsub/docs/get-started-with-web-sdk#standalone-example-of-websdk-initialization).
5. [Conduct verification](https://docs.sumsub.com/sumsub/docs/track-verification-activity) and [handle results](https://docs.sumsub.com/sumsub/docs/receive-verification-results).

> 📘 Note
>
> To initialize the WebSDK within the mobile app using `WebView`, make sure that:
>
> * `WebView` is able to access device local storage and initialize the camera. For older iOS versions, the camera can be accessed only from the Safari browser or WebView `SFSafariViewController`.
> * HTML5 video playback is allowed (we are using some instructions within `<video>` tags). If the video instructions are not played, try using `WebChromeClient` to enable video playback.
> * Autoplay in fullscreen mode is disabled, and `allowsInlineMediaPlayback` is set to `true` for `WebView` with running SDK.
> * Callbacks for file selection and camera invocations are correctly configured on the host application side (required for file uploads).
> * WebView has access to `window.localStorage` (`domStorageEnabled` on Android).

> To capture flows in WKWebView in iOS, `mediaTypesRequiringUserActionForPlayback` should be configured to allow camera/video playback without user action (i.e., disable the requirement), otherwise video may not start until the user interacts (e.g., toggling camera).

# Generate SDK access token

To generate an access token, use [this API method](https://docs.sumsub.com/sumsub/reference/generate-access-token) as the following example demonstrates:

```curl Request
curl --request POST \
     --url https://api.sumsub.com/resources/accessTokens/sdk \
     --header 'content-type: application/json' \
     --data '
            {
              "applicantIdentifiers": {
                "email": "john.doe@domain.com",
                "phone": "555-1111"
              },
              "ttlInSecs": 600,
              "userId": "johndoeID",
              "levelName": "basic-kyc-level"
            }
      '
```
```json Response
{
  "token": "eyJhbGciOiJub25lIn0.eyJqdGkiOiJfYWN0LTZmODI2ZTU0LTE2MzctNDViMS05NzMyLWY1MjZiN2YxNWE3YyIsInVybCI6Imh0dHBzOi8vYXBpLnN1bXN1Yi5jb20ifQ.",
  "userId": "johndoeID"
}
```

> 📘 Note
>
> * Provide a unique and meaningful `userId` parameter, which can be an external user ID in your system or an email address. If your `userId` or `levelName` contains reserved characters (e.g., `@`, `+`, white spaces as `%20`), they should be URL-encoded; otherwise, you may get a signature mismatch or just an invalid parameter value.
> * When generating an access token for [Local Data Processing](https://docs.sumsub.com/sumsub/docs/local-data-processing), use the regional domain. For example, `api.uae.sumsub.com`.  Further processing will be carried out in the region, which is guaranteed by our SDKs.
> * Authenticate all API requests as described in [this article](https://docs.sumsub.com/sumsub/reference/authentication).
> * For testing purposes, use an app token and secret key pair created in [Sandbox mode](https://docs.sumsub.com/sumsub/docs/sandbox-mode) to request authorization headers.
> * Make sure your integration code does not validate or analyze the access token content, as the format is not fixed and may undergo changes. The token must be treated as an arbitrary string with the maximum length of 1KB.
> * An access token for the applicant has limited access to the API, e.g., it is only valid for 1 applicant and cannot access other applicants. If you reuse access tokens, set up an access token expiration handler.

# Set up frontend integration

To integrate the WebSDK:

1. Install the NPM package.

```java npm
npm i @sumsub/websdk --save
```
```java yarn
yarn add @sumsub/websdk
```

2. Import the `snsWebSdk` module.

```javascript
import snsWebSdk from '@sumsub/websdk';
```

Alternatively, use the standalone package.

```html
<script src = "https://static.sumsub.com/idensic/static/sns-websdk-builder.js"></script>
```

3. Create a container for the WebSDK on your page.

```html
<!-- iframe will be inserted as a child element -->
<div id="sumsub-websdk-container"></div>
```

4. Initialize the WebSDK.

```javascript WebSDK 2.0
/**
 * @param accessToken - access token that you generated on the backend
 */
function launchWebSdk(accessToken) {
    let snsWebSdkInstance = snsWebSdk
        .init(
            accessToken,
            // token update callback, must return Promise
            // Access token expired
            // get a new one and pass it to the callback to re-initiate the WebSDK
            () => this.getNewAccessToken()
        )
        .withConf({
            lang: "en", //language of WebSDK texts and comments (ISO 639-1 format)
            theme: "dark" | "light",
        })
        .withOptions({ addViewportTag: false, adaptIframeHeight: true })
        // see below what kind of messages WebSDK generates
        .on("idCheck.onStepCompleted", (payload) => {
            console.log("onStepCompleted", payload);
        })
        .on("idCheck.onError", (error) => {
            console.log("onError", error);
        })
        .build();

    // you are ready to go:
    // just launch the WebSDK by providing the container element for it
    snsWebSdkInstance.launch("#sumsub-websdk-container");
}

function getNewAccessToken() {
    return Promise.resolve(newAccessToken); // get a new token from your backend
}
```
```javascript WebSDK 1.0
/**
 * @param accessToken - access token that you generated on the backend
 * @param customI18nMessages - customized locale messages for current session (not required)
 */
function launchWebSdk(accessToken, customI18nMessages) {
    let snsWebSdkInstance = snsWebSdk
        .init(
            accessToken,
            // token update callback, must return Promise
            // Access token expired
            // get a new one and pass it to the callback to re-initiate the WebSDK
            () => this.getNewAccessToken()
        )
        .withConf({
            lang: "en", //language of WebSDK texts and comments (ISO 639-1 format)
            i18n: customI18nMessages, //JSON of custom SDK Translations
            uiConf: {
                customCss: "https://url.com/styles.css",
                // URL to css file in case you need change it dynamically from the code
                // the similar setting at Customizations tab will rewrite customCss
                // you may also use to pass string with plain styles `customCssStr:`
            },
        })
        .withOptions({ addViewportTag: false, adaptIframeHeight: true })
        // see below what kind of messages WebSDK generates
        .on("idCheck.stepCompleted", (payload) => {
            console.log("stepCompleted", payload);
        })
        .on("idCheck.onError", (error) => {
            console.log("onError", error);
        })
        .build();

    // you are ready to go:
    // just launch the WebSDK by providing the container element for it
    snsWebSdkInstance.launch("#sumsub-websdk-container");
}

function getNewAccessToken() {
    return Promise.resolve(newAccessToken); // get a new token from your backend
}
```

> 📘 Note
>
> * Make sure that `accessToken` was provided to the SDK initialization function.
> * SDK's iframe resizes itself according to its container and SDK screen content, so the container itself shouldn't have a static size, but should adjust to the screen size. Try to use the `<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">` tags.

[block:html]
{
  "html": "<style>\n    .line {\n        border-top: 1px solid rgb(0 0 0 / 10%);\n        margin-bottom: -32px;\n        margin-top: 50px;\n    }\n</style>\n\n<div class=\"line\"></div>\n<form class=\"tabs\">\n    <input type=\"radio\" name=\"tabs\" id=\"tabContent2\" checked=\"checked\" onclick=\"openTab(event, 'tabContent2')\" />\n    <label for=\"tabContent2\">Attributes of WebSDK 2.0</label>\n    <div class=\"tab tabcontent active\">\n        <h4>ATTRIBUTES OF <code>withConf</code> PARAMETER</h4>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Name</th>\n                            <th>Type</th>\n                            <th>Required</th>\n                            <th>Description</th>\n                            <th>Default</th>\n                        </tr>\n                    </thead>                 \n                    <tr>\n                        <td>\n                            <p><code>lang</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p><a href=\"/docs/supported-sdk-languages\">Language</a> (ISO 639-1) in which the WebSDK texts and comments should be displayed.</p>\n                        </td>\n                        <td>\n                            <p><code>en</code></p>\n                        </td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>translationName</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Overrides the level translation value for a specific SDK run.</p>\n                        </td>\n                        <td>\n                            <p>N/A</p>\n                        </td>\n                    </tr>                    \n                    <tr>\n                        <td>\n                            <p><code>customizationName</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Overrides the level <a href=\"/docs/set-customization\">customization</a> value for a specific SDK run.</p>\n                        </td>\n                        <td>\n                            <p>N/A</p>\n                        </td>\n                    </tr>                   \n                    <tr>\n                        <td>\n                            <p><code>country</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td><p>Alpha-3 country code to prefill it on the document upload screen.</p></td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>theme</code></p>\n                        </td>\n                        <td><p><code>dark</code> or <code>light</code></p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Sets a light or dark theme. Set <code>'dark'|'light'</code> to match your website current theme. By default, with no theme attribute, the theme is automatically selected and follows the user device theme.</p>\n                        </td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>documentDefinitions</code></p>\n                        </td>\n                        <td><p>Object</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Pre-filled definitions on the <code>doCapture</code> screen.</p>\n                        </td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>autoSelectDocumentDefinitions</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Whether we should automatically select a document provided in <code>documentDefinitions</code>. If <code>true</code>, the Doc Type Selector screen will be skipped.</p>\n                        </td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>controlledNavigationBack</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Whether we allow to control the navigation of the SDK from the host application side. If <code>true</code>, then you can navigate back to the previous screen by calling <code>navigateBack()</code>.</p>\n                        </td>\n                        <td><p>N/A</p></td>\n                    </tr>                \n                </table>\n            </div>\n        </div>\n        <h4>STRUCTURE OF <code>documentDefinitions</code> PARAMETER</h4>\n        <p>The <code>documentDefinitions</code> parameter is a key-value object, where keys are <code>idDocSetType</code> and values are <code>documentDefinition</code>.</p>\n        <p>Possible values of <code>idDocSetType</code> are:</p>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Value</th>\n                            <th>Description</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY</code></p>\n                        </td>\n                        <td><p>Identity document step.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY2</code></p>\n                        </td>\n                        <td><p>Second identity document step.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY3</code></p>\n                        </td>\n                        <td><p>Third identity document step.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY4</code></p>\n                        </td>\n                        <td><p>Fourth identity document step.</p></td>\n                    </tr>\n                </table>\n            </div>\n        </div>\n        <p>Possible attributes of <code>documentDefinition</code> are:</p>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Name</th>\n                            <th>Type</th>\n                            <th>Required</th>\n                            <th>Description</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>country</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>Yes</p></td>\n                        <td><p>Alpha-3 country code.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>idDocType</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>Yes</p></td>\n                        <td><p>Document type.</p></td>\n                    </tr>\n                </table>\n            </div>\n        </div>\n        <h4>ATTRIBUTES OF <code>withOptions</code> PARAMETER</h4>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Name</th>\n                            <th>Type</th>\n                            <th>Required</th>\n                            <th>Description</th>\n                            <th>Default</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>addViewportTag</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Adds the <code>viewport</code> metatag for iFrame for mobile-optimized SDK adjustments.</p>\n                        </td>\n                        <td>\n                            <p><code>true</code></p>\n                        </td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>adaptIframeHeight</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td><p>Allows the SDK to adapt its height, depending on the size of the frame/container/page/screen.</p></td>\n                        <td>\n                            <p><code>true</code></p>\n                        </td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>enableScrollIntoView</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Controls the scrolling function within and outside of an SDK page:</p>\n                            <ul>\n                                <li><code>true</code> — The SDK page is scrolled up to the top every time the applicant changes pages in the SDK. Your website page is scrolled up as well.</li>\n                                <li><code>false</code> — The SDK page stays at the same position regardless of whether the applicant changes pages inside the SDK or not. Your website page is not scrolled.</li>\n                            </ul>\n                        </td>\n                        <td><p><code>true</code></p></td>\n                    </tr>    \n                </table>\n            </div>\n        </div>\n    </div>\n\n    <input type=\"radio\" name=\"tabs\" id=\"tabContent1\" onclick=\"openTab(event, 'tabContent1')\" />\n    <label for=\"tabContent1\">Attributes of WebSDK 1.0</label>\n    <div class=\"tab tabcontent\">\n        <h4>ATTRIBUTES OF <code>withConf</code> PARAMETER</h4>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Name</th>\n                            <th>Type</th>\n                            <th>Required</th>\n                            <th>Description</th>\n                            <th>Default</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>lang</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p><a href=\"/docs/supported-sdk-languages\">Language</a> (ISO 639-1) in which the WebSDK texts and comments should be displayed.</p>\n                        </td>\n                        <td>\n                            <p><code>en</code></p>\n                        </td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>country</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td><p>Alpha-3 country code to prefill it on the document upload screen.</p></td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>i18n</code></p>\n                        </td>\n                        <td><p>JSON</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Custom <a href=\"/docs/sdk-translations\">SDK translations</a> to change dynamically on the SDK initialization.</p>\n                        </td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>uiConf</code></p>\n                        </td>\n                        <td><p>Object</p></td>\n                        <td><p>No</p></td>\n                        <td><p>SDK custom configuration.</p></td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>documentDefinitions</code></p>\n                        </td>\n                        <td><p>Object</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Pre-filled definitions on the <code>doCapture</code> screen.</p>\n                        </td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                </table>\n            </div>\n        </div>\n        <h4>ATTRIBUTES OF <code>uiConf</code> PARAMETER</h4>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Name</th>\n                            <th>Type</th>\n                            <th>Required</th>\n                            <th>Description</th>\n                            <th>Default</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>customCss</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td><p>URL to your external CSS file for SDK to use during initialization.</p></td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>customCssStr</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>No</p></td>\n                        <td><p>Plain string with changes in CSS.</p></td>\n                        <td><p>N/A</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>scrollIntoView</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td><p>Disables/enables automatic scrolling on SDK screen switches.</p></td>\n                        <td>\n                            <p><code>true</code></p>\n                        </td>\n                    </tr>\n                </table>\n            </div>\n        </div>\n        <h4>STRUCTURE OF <code>documentDefinitions</code> PARAMETER</h4>\n        <p>The <code>documentDefinitions</code> parameter is a key-value object, where keys are <code>idDocSetType</code> and values are <code>documentDefinition</code>.</p>\n        <p>Possible values of <code>idDocSetType</code> are:</p>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Value</th>\n                            <th>Description</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY</code></p>\n                        </td>\n                        <td><p>Identity document step.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY2</code></p>\n                        </td>\n                        <td><p>Second identity document step.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY3</code></p>\n                        </td>\n                        <td><p>Third identity document step.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>IDENTITY4</code></p>\n                        </td>\n                        <td><p>Fourth identity document step.</p></td>\n                    </tr>\n                </table>\n            </div>\n        </div>\n        <p>Possible attributes of <code>documentDefinition</code> are:</p>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Name</th>\n                            <th>Type</th>\n                            <th>Required</th>\n                            <th>Description</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>country</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>Yes</p></td>\n                        <td><p>Alpha-3 country code.</p></td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>idDocType</code></p>\n                        </td>\n                        <td><p>String</p></td>\n                        <td><p>Yes</p></td>\n                        <td><p>Document type.</p></td>\n                    </tr>\n                </table>\n            </div>\n        </div>\n        <h4>ATTRIBUTES OF <code>withOptions</code> PARAMETER</h4>\n        <div class=\"rdmd-table\">\n            <div class=\"rdmd-table-inner\">\n                <table>\n                    <thead>\n                        <tr>\n                            <th>Name</th>\n                            <th>Type</th>\n                            <th>Required</th>\n                            <th>Description</th>\n                            <th>Default</th>\n                        </tr>\n                    </thead>\n                    <tr>\n                        <td>\n                            <p><code>addViewportTag</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td>\n                            <p>Adds the <code>viewport</code> metatag for iFrame for mobile-optimized SDK adjustments.</p>\n                        </td>\n                        <td>\n                            <p><code>true</code></p>\n                        </td>\n                    </tr>\n                    <tr>\n                        <td>\n                            <p><code>adaptIframeHeight</code></p>\n                        </td>\n                        <td><p>Boolean</p></td>\n                        <td><p>No</p></td>\n                        <td><p>Allows the SDK to adapt its height, depending on the size of the frame/container/page/screen.</p></td>\n                        <td>\n                            <p><code>true</code></p>\n                        </td>\n                    </tr>\n                </table>\n            </div>\n        </div>\n    </div>\n</form>"
}
[/block]

## React integration

To integrate with React:

1. Install `websdk-react`.

```shell
import SumsubWebSdk from '@sumsub/websdk-react'
```

2. Initialize the WebSDK.

```html
<SumsubWebSdk
  accessToken={accessToken}
  expirationHandler={accessTokenExpirationHandler}
  config={config}
  options={options}
  onMessage={messageHandler}
  onError={errorHandler}
/>
```

> 📘 Note
>
> Use a newly generated `accessToken` for initialization and prepare an expiration handler.

# Standalone example of WebSDK initialization

The following is a fully working example — change the `$ACCESS_TOKEN` variable with the appropriate value, save it to an HTML file, and open it in your browser.

```html WebSDK 2.0
<html>
    <head>
        <title>WebSDK CDN Example</title>
    </head>
    <body>
        <script src="https://static.sumsub.com/idensic/static/sns-websdk-builder.js"></script>
        <div id="sumsub-websdk-container"></div>
    </body>
</html>

<script>
function launchWebSdk(accessToken, applicantEmail, applicantPhone) {
    let snsWebSdkInstance = snsWebSdk
        .init(accessToken, () => this.getNewAccessToken())
        .withConf({
            lang: "en",
            email: applicantEmail,
            phone: applicantPhone,
        })
        .withOptions({ addViewportTag: false, adaptIframeHeight: true })
        .on("idCheck.onStepCompleted", (payload) => {
            console.log("onStepCompleted", payload);
        })
        .on("idCheck.onError", (error) => {
            console.log("onError", error);
        })
        .onMessage((type, payload) => {
            console.log("onMessage", type, payload);
        })
        .build();
    snsWebSdkInstance.launch("#sumsub-websdk-container");
}

// Requests a new access token from the backend side.
function getNewAccessToken() {
    return Promise.resolve($NEW_ACCESS_TOKEN);
}

launchWebSdk($ACCESS_TOKEN);
</script>
```
```html WebSDK 1.0
<html>
    <head>
        <title>WebSDK CDN Example</title>
    </head>
    <body>
        <script src="https://static.sumsub.com/idensic/static/sns-websdk-builder.js"></script>
        <div id="sumsub-websdk-container"></div>
    </body>
</html>

<script>
function launchWebSdk(accessToken, applicantEmail, applicantPhone) {
    let snsWebSdkInstance = snsWebSdk
        .init(accessToken, () => this.getNewAccessToken())
        .withConf({
            lang: "en",
            email: applicantEmail,
            phone: applicantPhone,
            i18n: { document: { subTitles: { IDENTITY: "Upload a document that proves your identity" } } },
            onMessage: (type, payload) => {
                console.log("WebSDK onMessage", type, payload);
            },
            uiConf: {
                customCssStr:
                    ":root {\n  --black: #000000;\n   --grey: #F5F5F5;\n  --grey-darker: #B2B2B2;\n  --border-color: #DBDBDB;\n}\n\np {\n  color: var(--black);\n  font-size: 16px;\n  line-height: 24px;\n}\n\nsection {\n  margin: 40px auto;\n}\n\ninput {\n  color: var(--black);\n  font-weight: 600;\n  outline: none;\n}\n\nsection.content {\n  background-color: var(--grey);\n  color: var(--black);\n  padding: 40px 40px 16px;\n  box-shadow: none;\n  border-radius: 6px;\n}\n\nbutton.submit,\nbutton.back {\n  text-transform: capitalize;\n  border-radius: 6px;\n  height: 48px;\n  padding: 0 30px;\n  font-size: 16px;\n  background-image: none !important;\n  transform: none !important;\n  box-shadow: none !important;\n  transition: all 0.2s linear;\n}\n\nbutton.submit {\n  min-width: 132px;\n  background: none;\n  background-color: var(--black);\n}\n\n.round-icon {\n  background-color: var(--black) !important;\n  background-image: none !important;\n}",
            },
            onError: (error) => {
                console.error("WebSDK onError", error);
            },
        })
        .withOptions({ addViewportTag: false, adaptIframeHeight: true })
        .on("idCheck.stepCompleted", (payload) => {
            console.log("stepCompleted", payload);
        })
        .on("idCheck.onError", (error) => {
            console.log("onError", error);
        })
        .onMessage((type, payload) => {
            console.log("onMessage", type, payload);
        })
        .build();
    snsWebSdkInstance.launch("#sumsub-websdk-container");
}

// Requests a new access token from the backend side.
function getNewAccessToken() {
    return Promise.resolve($NEW_ACCESS_TOKEN);
}

launchWebSdk($ACCESS_TOKEN);
</script>
```

# Security headers and embedding requirements

Security headers offer essential guidance to a client's browser regarding the secure handling of a website's content.

They serve as an additional protective measure, shielding your application from prevalent threats.

However, these headers can also force the browser to block the camera or microphone API at the document/iframe level, preventing your users from passing verification.

One of the most common scenarios is the situation when the user grants their consent for camera and microphone access as a part of the verification flow, but the embedding page sends a restrictive or invalid Permissions-Policy signal resulting in the “Permission denied” error.

Another is the situation when the user switches between the Web and Mobile SDK. On mobile, camera access is managed through the native OS permissions, bypassing browser restrictions, but on desktop there can still be the permissions error.

To avoid these situations, you need to explicitly allow camera and microphone access by adding: `camera=(self "https://api.sumsub.com"), microphone=(self "https://api.sumsub.com")`or `camera=*, microphone=*` to the Permissions-Policy header and ensuring that your Feature-Policy (if present) does not restrict camera initialization.

For example, the header cannot include: `camera 'none'`.