## [​](https://docs.cognigy.com/ai/administer/installation/identity-providers\#prerequisites)  Prerequisites

- An account with the admin role in Cognigy.AI.
- The organization ID of your Cognigy.AI organization, referred to as `<organization-id>` in the examples. You can copy this ID from the [My Profile](https://docs.cognigy.com/ai/administer/user-menu/my-profile) page by clicking **\> Copy Organization ID**.
- The [API base URL](https://docs.cognigy.com/ai/for-developers/developers/api-and-cli#api-base-url) of your Cognigy.AI installation, referred to as `<api-base-url>` in the examples.
- Your Cognigy.AI URL, referred to as `<cognigy-url>` in the examples. For example, for the trial environment, this URL is `https://trial.cognigy.ai/`.
- An [API key](https://docs.cognigy.com/ai/administer/user-menu/my-profile) for sending configuration requests to the Cognigy.AI API.
- Administrator access to the IdP tenant that you want to integrate with Cognigy.AI.
- For Okta, you need an X.509 certificate. For more information, read Okta’s [documentation about app certificate use](https://help.okta.com/oag/en-us/content/topics/access-gateway/about-application-certificate-use.htm).

## [​](https://docs.cognigy.com/ai/administer/installation/identity-providers\#limitations)  Limitations

- An organization can have only one SSO configuration. To replace an SSO configuration, delete it, then create another one. For more information, read [Change an SSO Configuration in Cognigy.AI](https://docs.cognigy.com/ai/administer/installation/single-sign-on-saml2#change-an-sso-configuration-in-cognigy-ai).
- Only Microsoft Entra ID and OneLogin support single logout for Cognigy.AI.

## [​](https://docs.cognigy.com/ai/administer/installation/identity-providers\#create-an-idp-app)  Create an IdP App

To configure an IdP app, follow these steps:

- Auth0 - OpenID Connect

- Auth0 - SAML 2.0

- Microsoft Entra ID

- Google

- Okta

- OneLogin

1. Log in to the [Auth0 Dashboard](https://manage.auth0.com/) and select your tenant.
2. In the left-side menu, go to **Applications > Applications** and click **\+ Create Application**.
3. Enter a name, for example, `Cognigy.AI`, select **Regular Web Applications** as the app type, and click **Create**.
4. Go to the **Settings** tab and copy the values from the fields in the **Basic Information** section. You will use them later to [configure the IdP in Cognigy.AI](https://docs.cognigy.com/ai/administer/installation/identity-providers#configure-sso-in-cognigy-ai):   - **Domain** — used in the `idpIssuer` parameter in the request payload.
   - **Client ID** — used in the `idpClientId` parameter in the request payload.
   - **Client Secret** — used in the `idpClientSecret` parameter in the request payload.
5. On the **Settings** tab, configure the following using the API base URL and organization ID from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section:   - **Application Login URI** — enter `https://<api-base-url>/auth/oidc/callback/<organization-id>`.
   - **Allowed Callback URLs** — enter `https://<api-base-url>/auth/oidc/login/callback/<organization-id>`.
   - **Allowed Logout URLs** — enter `https://<api-base-url>/logout/<organization-id>`.
   - **Allowed Web Origins** — enter `https://*.cognigy.ai`.
   - **Allowed Origins (CORS)** — enter `https://*.cognigy.ai`.

1

Set Up an App

1. Log in to the [Auth0 Dashboard](https://manage.auth0.com/) and select your tenant.
2. In the left-side menu, go to **Applications > Applications** and click **\+ Create Application**.
3. Enter a name, for example, `Cognigy.AI`, select **Single Page Web Applications** as the app type, and click **Create**.
4. Go to the **Settings** tab, configure the following using the API base URL and organization ID from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section:   - **Application Login URI** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **Allowed Callback URLs** — enter `https://<api-base-url>/auth/oidc/login/callback/<organization-id>`.
5. On the **Addons** tab, activate the **SAML2 Web App** add-on. Auth0 opens the add-on settings dialog. From the **Usage** tab, copy and save the values from the following fields for later use in the API request payload to [configure the IdP in Cognigy.AI](https://docs.cognigy.com/ai/administer/installation/identity-providers#configure-sso-in-cognigy-ai):   - **Issuer** — used in the `idpIssuer` parameter in the request payload.
   - **Identity Provider Login URL** — used in the `idpLoginEndpoint` parameter in the request payload.
   - **Identity Provider Certificate** — used in the `idpCertificate` parameter in the request payload. Click **Download Auth0 certificate**. Base64-encode the certificate without line breaks. You can use the following terminal command:

PowerShell

Bash (macOS)

Bash (Linux)

```
     [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\path-to-certificate"))
     ```

```
     base64 -i ./<path-to-certificate> | tr -d '\n'
     ```

```
     cat ./<path-to-certificate> | base64 -w0
     ```

2

Map Roles

For each user which you want to apply SSO to, set `user_metadata` to map the user’s name and Cognigy.AI role. To do so, follow these steps:

1. Go to **User Management > Users**, select the user, scroll to the **Metadata** section, and paste the following JSON into the **user\_metadata** field:

```
{
     "family_name": "<LAST NAME>",
     "given_name": "<FIRST NAME>",
     "role": "<COGNIGY_ROLE>"
}
```

The `role` value must match a [role in Cognigy.AI](https://docs.cognigy.com/ai/administer/access/admin-center/access-control), for example, `admin` or `base_role`.
2. Go to **Actions > Library**, click **Create Action**, and configure the following:

- **Name** — enter a name.
- **Login / Post Login** — activate this option.
- In the editor, paste the following code:

```
exports.onExecutePostLogin = async (event, api) => {
    const userMetadata = event.user.user_metadata || {};

api.samlResponse.setAttribute(
      "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
      event.user.email
    );
    api.samlResponse.setAttribute("firstName", userMetadata.given_name || "");
    api.samlResponse.setAttribute("lastName", userMetadata.family_name || "");
    api.samlResponse.setAttribute("role", userMetadata.role || "");
};
```

3. Deploy the Action.

1

Set Up an App

1. Log in to the [Azure portal](https://portal.azure.com/) with an administrator account and navigate to **Microsoft Entra ID**.
2. In the top bar, click **\+ Add** and select **Enterprise applications**. The **Browse Microsoft Entra Gallery** page opens.
3. In the top bar, click **\+ Create your own application**.
4. Enter a name, for example, `Cognigy.AI`, select **Integrate any other app you don’t find in the gallery (Non-gallery)**, and click **Create**.
5. On the new app page, open **Single sign-on** in the left navigation and select **SAML** as the sign-on method.
6. In the **Basic SAML Configuration** section, click **Edit** and configure the following:   - **Identifier (Entity ID)** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **Reply URL (Assertion Consumer Service URL)** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **Sign on URL** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - _(Optional)_ **Logout Url** — enter `https://<cognigy-url>/slo/<organization-id>`.
7. Click **Save**.

2

Map User Attributes

1. In the **User Attributes and Claims** section, click **Edit** and confirm that the following claims are mapped to the user’s profile attributes:

| Claim name | Value |
| --- | --- |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress` | `user.mail` |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname` | `user.givenname` |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname` | `user.surname` |

Cognigy.AI uses the email claim to identify the user and to create the Cognigy.AI account on the first login.

3

Get Authentication Data

1. In the **SAML Signing Certificate** section, locate **Certificate (Base64)** and click **Download**. Save the file locally. Use this certificate as `idpCertificate` in the API request to [configure the IdP in Cognigy.AI](https://docs.cognigy.com/ai/administer/installation/identity-providers#configure-sso-in-cognigy-ai). You need to encode the certificate as base64 without newlines beforehand. To do so, use the following terminal command:

PowerShell

Bash (macOS)

Bash (Linux)

```
[Convert]::ToBase64String([IO.File]::ReadAllBytes(".\path-to-certificate"))
```

```
base64 -i ./<path-to-certificate> | tr -d '\n'
```

```
cat ./<path-to-certificate> | base64 -w0
```

2. In the **Set up `<application name>`** section, copy the following values to be used in the API request to [configure the IdP in Cognigy.AI](https://docs.cognigy.com/ai/administer/installation/identity-providers#configure-sso-in-cognigy-ai):

- **Login URL** — used in the `idpLoginEndpoint` parameter in the request payload.
- _(Optional)_ **Logout URL** — used in the `idpLogoutUrl` parameter in the request payload when you enable single logout.

4

Assign Roles

1. In the top bar, search for `App registrations` and select this option.
2. In the **All applications** tab, search for the app you created and select it.
3. In the left-side menu, go to **Manage > Manifest** and deactivate the default `User` and `msiam_access` roles. To do so:   1. Set `isEnabled` to `false` for the `User` and `msiam_access` roles, for example:

```
         "appRoles": [\
           {\
             "allowedMemberTypes": [\
               "User"\
             ],\
             "description": "User",\
             "displayName": "User",\
             "id": "18d14569-c3bd-439b-9a66-3a2aee01d14f",\
             "isEnabled": false,\
             "origin": "Application",\
             "value": null\
           },\
           {\
             "allowedMemberTypes": [\
               "User"\
             ],\
             "description": "msiam_access",\
             "displayName": "msiam_access",\
             "id": "b9632174-c057-4f7e-951b-be3adc52bfe6",\
             "isEnabled": false,\
             "origin": "Application",\
             "value": null\
           }\
         ]
         ```

2. In the left-side menu, go to **Manage > App roles**, select the **User** role, and click **Delete** on the right-side pane. Do the same for the `msiam_access` role.
4. Paste the following JSON code in the `appRoles` array:

Roles Array

```
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Admin",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc1",
     "isEnabled": true,
     "description": "The Admin role in Cognigy.AI",
     "value": "admin"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "API Keys",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc2",
     "isEnabled": true,
     "description": "The apiKeys role in Cognigy.AI",
     "value": "apiKeys"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Base",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc3",
     "isEnabled": true,
     "description": "The base role in Cognigy.AI",
     "value": "base_role"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Full Support User",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc4",
     "isEnabled": true,
     "description": "Admin privileges, no user assignments in Cognigy.AI",
     "value": "fullSupportUser"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "OData",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc5",
     "isEnabled": true,
     "description": "The OData role in Cognigy.AI",
     "value": "odata"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Project Manager",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc6",
     "isEnabled": true,
     "description": "The Project Manager role in Cognigy.AI",
     "value": "projectManager"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "User Manager",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc7",
     "isEnabled": true,
     "description": "The User Manager role in Cognigy.AI",
     "value": "userManager"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Administrator",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc8",
     "isEnabled": true,
     "description": "The Administrator role in Live Agent",
     "value": "liveAgentAdmin"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Agent",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bc9",
     "isEnabled": true,
     "description": "The Agent role in Live Agent",
     "value": "liveAgentAgent"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Supervisor",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bd1",
     "isEnabled": true,
     "description": "The Supervisor role in Live Agent",
     "value": "liveagentSupervisor"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "View user details",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bd2",
     "isEnabled": true,
     "description": "The role to view user details in Cognigy.AI",
     "value": "userDetailsViewer"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Voice Gateway User",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bd3",
     "isEnabled": true,
     "description": "The Account scope in Voice Gateway",
     "value": "voiceGatewayUser"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Basic Support User",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bd4",
     "isEnabled": true,
     "description": "Partial Admin, read-only, no assignments, no OData/API, no Knowledge AI in Cognigy.AI",
     "value": "basicSupportUser"
},
{
     "allowedMemberTypes": [\
       "User"\
     ],
     "displayName": "Project Assigner",
     "id": "8d17fe88-c0ca-4903-ae2a-a51098998bd5",
     "isEnabled": true,
     "description": "Assigns Agents, read-only access, no global roles, limited features in Cognigy.AI",
     "value": "projectAssigner"
}
```

5. In the left-side menu, go to **Users and groups** and assign the app to the users or groups that must have access to Cognigy.AI through SSO.

1

Add a Custom Attribute

You need to add a custom attribute that Cognigy.AI uses when the user logs in for the first time. To do so, follow these steps:

1. Log in to the [Google Admin console](https://admin.google.com/).
2. In the left-side menu, go to **Directory > Users**.
3. At the top of the **Users** list, click **More options > Manage user attributes**.
4. Click the **Add Custom Attribute** button and configure the following:

- **Category** — enter a unique name to identify the custom attribute, for example, `Cognigy.AI SSO`.
   - **Description** — enter a relevant description of the custom attribute.
   - In the **Custom fields** section, configure three custom fields with the following values:

| Name | Info type | Visibility | Number of values |
     | --- | --- | --- | --- |
     | First Name | Text | Visible to user and admin | Single value |
     | Last Name | Text | Visible to user and admin | Single value |
     | Role | Text | Visible to user and admin | Single value |

If a user doesn’t have a role assigned, Cognigy.AI assigns `base_role` to the user.

5. Click **Add**.

2

Set Up an App

1. In the left-side menu, go to **Apps > SAML Apps**.
2. Click the plus button in the lower-right corner and select **Setup My Own Custom App**.
3. In the **Google IdP Information** dialog, copy the **SSO URL** value and download the certificate. You’ll use the SSO URL as `idpLoginEndpoint` and the certificate as `idpCertificate` in the API request to [configure the IdP in Cognigy.AI](https://docs.cognigy.com/ai/administer/installation/identity-providers#configure-sso-in-cognigy-ai). You need to encode the certificate as base64 without newlines beforehand. To do so, use the following terminal command:

PowerShell

Bash (macOS)

Bash (Linux)

```
[Convert]::ToBase64String([IO.File]::ReadAllBytes(".\path-to-certificate"))
```

```
base64 -i ./<path-to-certificate> | tr -d '\n'
```

```
cat ./<path-to-certificate> | base64 -w0
```

Click **Next**.
4. Enter a name for the app, for example, `Cognigy.AI`, and click **Next**.
5. On the service provider details page, configure the following:

- **ACS URL** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **Entity ID** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **Signed Response** — select the checkbox.
   - **Name ID Format** — set to `EMAIL`.

Click **Next**.
6. On the **Attribute Mapping** page, add the following attribute mappings so that Cognigy.AI receives the user’s first name, last name, and role from Google:

| Service Provider Attribute | Custom Attribute | Field |
| --- | --- | --- |
| `firstName` | Cognigy.AI SSO | First Name |
| `lastName` | Cognigy.AI SSO | Last Name |
| `role` | Cognigy.AI SSO | Role |

7. Click **Finish**, then activate the app for the users or organizational units that must have access to Cognigy.AI through Google SSO.

1

Set Up an App

1. Log in to your [Okta Admin Console](https://login.okta.com/) with an administrator account.
2. In the left-side menu, go to **Applications > Applications** and click **Create New App**.
3. Select **SAML 2.0** as the sign-on method and click **Create**.
4. On the **General Settings** tab, enter an app name, for example, `Cognigy.AI SSO`, optionally upload a logo, and click **Next**.
5. On the **Configure SAML** tab, configure the following:   - **Single sign-on URL** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **Use this for Recipient URL and Destination URL** — keep selected.
   - **Audience URI (SP Entity ID)** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **Name ID format** — select **Unspecified**.
   - **Application username** — select **Email**.
   - **Update application username on** — select **Create and update**.
6. _(Optional)_ To encrypt SAML requests, click **Show Advanced Settings**, set **Assertion Encryption** to **Encrypted**, and [upload an X.509 certificate](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites). You will need the private key of this certificate to register the IdP in Cognigy.AI.

2

Map User Attributes

1. In the **Attribute Statements** section, add the following attributes so that Cognigy.AI receives the user profile data it needs to create the account:

| Name | Name format | Value |
| --- | --- | --- |
| `email` | Unspecified | `user.email` |
| `firstName` | Unspecified | `user.firstName` |
| `lastName` | Unspecified | `user.lastName` |

Click **Next**.
2. On the **Feedback** tab, select **I’m an Okta customer adding an internal app** and click **Finish**.

3

Get Authentication Data

1. On the **Applications** page, select the app you created, then open the **Sign On** tab.
2. In the **SAML Signing Certificates** section, click **View Setup Instructions** or **Identity Provider metadata** and copy the following values:   - **Identity Provider Single Sign-On URL** — used in the `idpLoginEndpoint` parameter in the request payload.
   - **Identity Provider Issuer** — used in the `idpIssuer` parameter in the request payload.
   - **X.509 Certificate** — used in the `idpCertificate` parameter in the request payload. You need to encode the certificate as base64 without newlines beforehand. If you enabled SAML request encryption, you also need to encode the private key as base64. You can use the following terminal command:

PowerShell

Bash (macOS)

Bash (Linux)

```
     [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\path-to-certificate-or-private-key"))
     ```

```
     base64 -i ./<path-to-certificate-or-private-key> | tr -d '\n'
     ```

```
     cat ./<path-to-certificate-or-private-key> | base64 -w0
     ```

4

Assign Users

1. In the left-side menu of the Admin Console, go to **Directory > Profile Editor**, and click **Profile** next to the profile of the app you created.
2. Click **Add Attribute** and configure the following:   - **Data type** — select **string**.
   - **Display name** — enter `Role`.
   - **Variable name** — enter `role`.
   - _(Optional)_ **Description** — enter a relevant description, for example, `The role of the user in Cognigy.AI`.
   - **Enum** — activate **Define enumerated list of values**.
   - **Attribute member** — enter a display name and the value of the role to which SSO applies, for example, `Base Role` and `base_role`. The value must match a [role in Cognigy.AI](https://docs.cognigy.com/ai/administer/access/admin-center/access-control).
   - **Attribute required** — select this option.

Click **Save**.
3. Go to **Applications > Applications** and select the app you created.
4. On the **Assignments** tab, click the Edit button next to the user’s name and assign the role they should have in Cognigy.AI. This user can log in via SSO.

1

Set Up an App

1. Log in to your OneLogin Administration portal with an administrator account.
2. In the top bar, click **Applications**, then click **Add App** in the upper-right corner.
3. Search for `SAML Custom Connector (Advanced)` in the search field and select this option.
4. In the **Display Name** field, enter a name that identifies the integration, for example, `Cognigy.AI SSO`. Optionally upload icons. Click **Save**.
5. On the new app page, click the **Configuration** tab in the left-side menu and configure the following:

- **ACS (Consumer) URL** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - **ACS (Consumer) URL Validator** — enter `https://<api-base-url>/auth/saml/login/<organization-id>`.
   - _(Optional)_ **Single Logout URL** — enter `https://<cognigy-url>/slo/<organization-id>`.

Click **Save**.
6. In the left-side menu, go to the **Parameters** tab, configure the following parameter and value pairs, and select the **Include in SAML assertion** option for each pair:

| Parameter | Value |
| --- | --- |
| `email` | Email |
| `firstName` | First Name |
| `lastName` | Last Name |
| `role` | User Role |

Click **Save** to apply the attribute mapping.

2

Get Authentication Data

1. In the left-side menu, go to the **SSO** tab and copy the following values:   - **X.509 Certificate** — click **View Details** and download the certificate. You will use its contents as `idpCertificate`. You need to encode the certificate as base64 without newlines beforehand. You can use the following terminal command:

PowerShell

Bash (macOS)

Bash (Linux)

```
        [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\path-to-certificate"))
        ```

```
        base64 -i ./<path-to-certificate> | tr -d '\n'
        ```

```
        cat ./<path-to-certificate> | base64 -w0
        ```

- **Issuer URL** — used in the `idpIssuer` parameter in the request payload.
   - **SAML 2.0 Endpoint (HTTP)** — used in the `idpLoginEndpoint` parameter in the request payload.
   - _(Optional)_ **SLO Endpoint** — used in the `idpLogoutEndpoint` parameter in the request payload.
2. In the left-side menu, navigate to **Users > Roles** and click **New Role**.
3. Add the following Cognigy.AI roles one by one, select the app you created, and click **Save**:   - `admin`
   - `apiKeys`
   - `base_role`
   - `livechat`
   - `odata`
   - `projectManager`
   - `userManager`
4. In the left-side menu, go to the **Users** tab and select a user for SSO. On the user page, enter the role they have in Cognigy.AI in the **role** field. The role must match the roles you configured in step 3.
5. Click **Save**. The user can log in via SSO.

## [​](https://docs.cognigy.com/ai/administer/installation/identity-providers\#configure-sso-in-cognigy-ai)  Configure SSO in Cognigy.AI

After the SSO app is ready, use the [`POST /v2.0/identityprovider/configure`](https://docs.cognigy.com/api-reference/identity-providers/set-up-an-identity-provider) method to register the SSO configuration in Cognigy.AI.

- Auth0 - OpenID Connect

- Auth0 - SAML 2.0

- Microsoft Entra ID

- Google

- Okta

- OneLogin

Send the API request with the following parameters:

- `X-API-Key` header — the API key from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section.
- `idpIssuer` — the Domain value you copied earlier from [the **Settings** tab](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- `idpClientId` — the Client ID value you copied earlier from [the **Settings** tab](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- `idpClientSecret` — the Client Secret value you copied earlier from [the **Settings** tab](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).

API Request Example

-X POST \

JavaScript

Python

```
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-token>" \
  -d '{
    "idpType": "oidc",
    "idpIssuer": "<DOMAIN>",
    "idpClientId": "<CLIENT ID>",
    "idpClientSecret": "<CLIENT SECRET>",
    "idpIdTokenSignedResponseAlg": "RS256",
    "idpTokenEndpointAuthMethod": "client_secret_basic"
  }'
```

```
const response = await fetch("https://<api-base-url>/v2.0/identityprovider/configure", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "<your-api-token>"
  },
  body: JSON.stringify({
    idpType: "oidc",
    idpIssuer: "<DOMAIN>",              // Domain from the Auth0 app Settings tab
    idpClientId: "<CLIENT ID>",         // Client ID from the Auth0 app Settings tab
    idpClientSecret: "<CLIENT SECRET>", // Client Secret from the Auth0 app Settings tab
    idpIdTokenSignedResponseAlg: "RS256",
    idpTokenEndpointAuthMethod: "client_secret_basic"
  })
});
```

```
import requests

response = requests.post(
    "https://<api-base-url>/v2.0/identityprovider/configure",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "<your-api-token>"
    },
    json={
        "idpType": "oidc",
        "idpIssuer": "<DOMAIN>",                # Domain from the Auth0 app Settings tab
        "idpClientId": "<CLIENT ID>",           # Client ID from the Auth0 app Settings tab
        "idpClientSecret": "<CLIENT SECRET>",   # Client Secret from the Auth0 app Settings tab
        "idpIdTokenSignedResponseAlg": "RS256",
        "idpTokenEndpointAuthMethod": "client_secret_basic"
    }
)
```

Send the API request with the following data:

- `X-API-Key` header — the API key from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section.
- `idpIssuer` — the Issuer value you copied earlier from [the **Usage** tab of the **SAML2 Web App** add-on](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- `idpLoginEndpoint` — the Identity Provider Login URL you copied earlier from [the **Usage** tab of the **SAML2 Web App** add-on](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- `idpCertificate` — the Identity Provider Certificate you copied earlier from [the **Usage** tab of the **SAML2 Web App** add-on](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app), including the `BEGIN`/`END` markers, with real line breaks replaced by `\n`.
- `idpIdentifierFormat` — the NameID format. Use `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress` to match the add-on settings.

API Request Example

-X POST \

JavaScript

Python

```
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-token>" \
  -d '{
    "idpType": "saml",
    "idpIssuer": "urn:<your-tenant>.auth0.com",
    "idpLoginEndpoint": "https://<your-tenant>.auth0.com/samlp/<client-id>",
    "idpCertificate": "-----BEGIN CERTIFICATE-----\n<certificate-body>\n-----END CERTIFICATE-----",
    "idpIdentifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
  }'
```

```
const response = await fetch("https://<api-base-url>/v2.0/identityprovider/configure", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "<your-api-token>"
  },
  body: JSON.stringify({
    idpType: "saml",
    idpLoginEndpoint: "https://<your-tenant>.auth0.com/samlp/<client-id>",                          // Identity Provider Login URL from the Auth0 add-on Usage tab
    idpIssuer: "urn:<your-tenant>.auth0.com",                                                    // Identity Provider Issuer from the Auth0 add-on Usage tab
    idpCertificate: "-----BEGIN CERTIFICATE-----\n<certificate-body>\n-----END CERTIFICATE-----",      // Identity Provider Certificate from the Auth0 add-on Usage tab
    idpIdentifierFormat: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
  })
});
```

```
import requests

response = requests.post(
    "https://<api-base-url>/v2.0/identityprovider/configure",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "<your-api-token>"
    },
    json={
        "idpType": "saml",
        "idpLoginEndpoint": "https://<your-tenant>.auth0.com/samlp/<client-id>",                          # Identity Provider Login URL from the Auth0 add-on Usage tab
        "idpIssuer": "urn:<your-tenant>.auth0.com",                                                    # Identity Provider Issuer from the Auth0 add-on Usage tab
        "idpCertificate": "-----BEGIN CERTIFICATE-----\n<certificate-body>\n-----END CERTIFICATE-----",      # Identity Provider Certificate from the Auth0 add-on Usage tab
        "idpIdentifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
    }
)
```

Send the API request with the following data:

- `X-API-Key` header — the API key from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section.
- `idpIssuer` — use `https://<api-base-url>/auth/saml/login/<organization-id>`.
- `idpLoginEndpoint` — the Login URL you copied earlier from the **Set up `<application name>`** section.
- `idpCertificate` — the certificate you downloaded earlier from the **SAML Signing Certificate** section, base64-encoded as a single continuous string with no line breaks.
- _(Optional)_`idpLogoutUrl` — the Logout URL you copied earlier from the **Set up `<application name>`** section.

API Request Example

cURL

JavaScript

Python

```
curl -X POST "https://<api-base-url>/v2.0/identityprovider/configure" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-token>" \
  -d '{
    "idpType": "saml",
    "idpIssuer": "https://<api-base-url>/auth/saml/login/<organization-id>",
    "idpLoginEndpoint": "https://login.microsoftonline.com/4a7853bd-xxxx-xxxx-xxxx-xxxxxxxxxxxx/saml2",
    "idpCertificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...",
    "idpLogoutUrl": "https://login.microsoftonline.com/4a7853bd-xxxx-xxxx-xxxx-xxxxxxxxxxxx/saml2"
  }'
```

```
const response = await fetch("https://<api-base-url>/v2.0/identityprovider/configure", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "<your-api-token>"
  },
  body: JSON.stringify({
    idpType: "saml",
    idpIssuer: "https://<api-base-url>/auth/saml/login/<organization-id>",                                // Cognigy.AI SSO URL
    idpLoginEndpoint: "https://login.microsoftonline.com/4a7853bd-xxxx-xxxx-xxxx-xxxxxxxxxxxx/saml2",    // Login URL from the Set up `<application name>` section
    idpCertificate: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...",                                            // Base64-encoded contents of the downloaded .crt file
    idpLogoutUrl: "https://login.microsoftonline.com/4a7853bd-xxxx-xxxx-xxxx-xxxxxxxxxxxx/saml2"          // Logout URL from the Set up `<application name>` section (optional, for SP-initiated SLO)
  })
});
```

```
import requests

response = requests.post(
    "https://<api-base-url>/v2.0/identityprovider/configure",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "<your-api-token>"
    },
    json={
        "idpType": "saml",
        "idpIssuer": "https://<api-base-url>/auth/saml/login/<organization-id>",                                # Cognigy.AI SSO URL
        "idpLoginEndpoint": "https://login.microsoftonline.com/4a7853bd-xxxx-xxxx-xxxx-xxxxxxxxxxxx/saml2",    # Login URL from the Set up `<application name>` section
        "idpCertificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t...",                                            # Base64-encoded contents of the downloaded .crt file
        "idpLogoutUrl": "https://login.microsoftonline.com/4a7853bd-xxxx-xxxx-xxxx-xxxxxxxxxxxx/saml2"          # Logout URL from the Set up `<application name>` section (optional, for SP-initiated SLO)
    }
)
```

Don’t include the PEM header, the PEM footer, or any newline characters in the certificate you submit to Cognigy.AI. A malformed certificate string causes the SSO configuration request to fail.

Send the API request with the following data:

- `X-API-Key` header — the API key from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section.
- `idpIssuer` — use `https://<api-base-url>/auth/saml/login/<organization-id>`.
- `idpLoginEndpoint` — the **SSO URL** value you copied earlier from the **Google IdP Information** dialog.
- `idpCertificate` — the certificate you downloaded earlier from the **Google IdP Information** dialog, base64-encoded as a single continuous string with no line breaks.

API Request Example

cURL

JavaScript

Python

```
curl -X POST "https://<api-base-url>/v2.0/identityprovider/configure" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-token>" \
  -d '{
    "idpType": "saml",
    "idpIssuer": "https://<api-base-url>/auth/saml/login/<organization-id>",
    "idpLoginEndpoint": "https://accounts.google.com/o/saml2/idp?idpid=XXXX",
    "idpCertificate": "MIIDdTCCAl2gAwIBAgIJAKx..."
  }'
```

```
const response = await fetch("https://<api-base-url>/v2.0/identityprovider/configure", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "<your-api-token>"
  },
  body: JSON.stringify({
    idpType: "saml",
    idpIssuer: "https://<api-base-url>/auth/saml/login/<organization-id>",   // Cognigy.AI SSO URL
    idpLoginEndpoint: "https://accounts.google.com/o/saml2/idp?idpid=XXXX",  // SSO URL from Google IdP Information dialog in the Google Admin console
    idpCertificate: "MIIDdTCCAl2gAwIBAgIJAKx..."                              // Certificate from Google IdP Information dialog, base64-encoded on a single line
  })
});
```

```
import requests

response = requests.post(
    "https://<api-base-url>/v2.0/identityprovider/configure",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "<your-api-token>"
    },
    json={
        "idpType": "saml",
        "idpIssuer": "https://<api-base-url>/auth/saml/login/<organization-id>",    # Cognigy.AI SSO URL
        "idpLoginEndpoint": "https://accounts.google.com/o/saml2/idp?idpid=XXXX",   # SSO URL from Google IdP Information dialog in the Google Admin console
        "idpCertificate": "MIIDdTCCAl2gAwIBAgIJAKx..."                               # Certificate from Google IdP Information dialog, base64-encoded on a single line
    }
)
```

Send the API request with the following data:

- `X-API-Key` header — the API key from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section.
- `idpIssuer` — the Identity Provider Issuer value you copied [from the SAML setup instructions page](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- `idpLoginEndpoint` — the Identity Provider Single Sign-On URL value you copied [from the SAML setup instructions page](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- For encrypted SAML requests:
  - `idpCertificate` — X.509 Certificate you uploaded under **Show Advanced Settings > Assertion Encryption**, base64-encoded as a single continuous string with no line breaks.
  - `decryptionPrivateKey` — the private key matching the X.509 certificate you [uploaded](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app) under **Show Advanced Settings > Assertion Encryption** and base64-encoded as a single continuous string.

API Request Example (Without Encryption)

cURL

JavaScript

Python

```
curl -X POST "https://<api-base-url>/v2.0/identityprovider/configure" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-token>" \
  -d '{
    "idpType": "saml",
    "idpIssuer": "<OKTA_IDENTITY_PROVIDER_ISSUER>",
    "idpLoginEndpoint": "<OKTA_SINGLE_SIGN_ON_URL>"
  }'
```

```
const response = await fetch("https://<api-base-url>/v2.0/identityprovider/configure", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "<your-api-token>"
  },
  body: JSON.stringify({
    idpType: "saml",
    idpIssuer: "<OKTA_IDENTITY_PROVIDER_ISSUER>",     // Identity Provider Issuer from the Okta Sign On tab
    idpLoginEndpoint: "<OKTA_SINGLE_SIGN_ON_URL>"        // Identity Provider Single Sign-On URL from the Okta Sign On tab
  })
});
```

```
import requests

response = requests.post(
    "https://<api-base-url>/v2.0/identityprovider/configure",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "<your-api-token>"
    },
    json={
        "idpType": "saml",
        "idpIssuer": "<OKTA_IDENTITY_PROVIDER_ISSUER>",     # Identity Provider Issuer from the Okta Sign On tab
        "idpLoginEndpoint": "<OKTA_SINGLE_SIGN_ON_URL>"        # Identity Provider Single Sign-On URL from the Okta Sign On tab
    }
)
```

API Request Example (With Encryption)

cURL

JavaScript

Python

```
curl -X POST "https://<api-base-url>/v2.0/identityprovider/configure" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-token>" \
  -d '{
    "idpType": "saml",
    "idpIssuer": "<OKTA_IDENTITY_PROVIDER_ISSUER>",
    "idpLoginEndpoint": "<OKTA_SINGLE_SIGN_ON_URL>",
    "idpCertificate": "<OKTA_X509_CERTIFICATE>",
    "decryptionPrivateKey": "<OKTA_PRIVATE_KEY>"
  }'
```

```
const response = await fetch("https://<api-base-url>/v2.0/identityprovider/configure", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "<your-api-token>"
  },
  body: JSON.stringify({
    idpType: "saml",
    idpIssuer: "<OKTA_IDENTITY_PROVIDER_ISSUER>",     // Identity Provider Issuer from the Okta Sign On tab
    idpLoginEndpoint: "<OKTA_SINGLE_SIGN_ON_URL>",    // Identity Provider Single Sign-On URL from the Okta Sign On tab
    idpCertificate: "<OKTA_X509_CERTIFICATE>",        // X.509 Certificate from the Okta Sign On tab, base64-encoded on a single line
    decryptionPrivateKey: "<OKTA_PRIVATE_KEY>"        // Private key matching the certificate uploaded to Okta, base64-encoded on a single line
  })
});
```

```
import requests

response = requests.post(
    "https://<api-base-url>/v2.0/identityprovider/configure",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "<your-api-token>"
    },
    json={
        "idpType": "saml",
        "idpIssuer": "<OKTA_IDENTITY_PROVIDER_ISSUER>",     # Identity Provider Issuer from the Okta Sign On tab
        "idpLoginEndpoint": "<OKTA_SINGLE_SIGN_ON_URL>",       # Identity Provider Single Sign-On URL from the Okta Sign On tab
        "idpCertificate": "<OKTA_X509_CERTIFICATE>",        # X.509 Certificate from the Okta Sign On tab, base64-encoded on a single line
        "decryptionPrivateKey": "<OKTA_PRIVATE_KEY>"        # Private key matching the certificate uploaded to Okta, base64-encoded on a single line
    }
)
```

Send the API request with the following data:

- `X-API-Key` header — the API key from the [Prerequisites](https://docs.cognigy.com/ai/administer/installation/identity-providers#prerequisites) section.
- `idpIssuer` — the Issuer URL you copied earlier from [the **SSO** tab of the OneLogin app](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- `idpLoginEndpoint` — the SAML 2.0 Endpoint (HTTP) you copied earlier from [the **SSO** tab of the OneLogin app](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).
- `idpCertificate` — the X.509 Certificate you encoded earlier from [the **SSO** tab of the OneLogin app](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app), base64-encoded as a single continuous string with no line breaks.
- _(Optional)_`idpLogoutEndpoint` — the SLO Endpoint you copied earlier from [the **SSO** tab of the OneLogin app](https://docs.cognigy.com/ai/administer/installation/identity-providers#create-an-idp-app).

API Request Example

cURL

JavaScript

Python

```
curl -X POST "https://<api-base-url>/v2.0/identityprovider/configure" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: <your-api-token>" \
  -d '{
    "idpType": "saml",
    "idpIssuer": "https://app.onelogin.com/saml/metadata/<id>",
    "idpLoginEndpoint": "https://<subdomain>.onelogin.com/trust/saml2/http-post/sso/<id>",
    "idpCertificate": "<ONELOGIN_X509_CERTIFICATE>",
    "idpLogoutEndpoint": "https://<subdomain>.onelogin.com/trust/saml2/http-redirect/slo/<id>"
  }'
```

```
const response = await fetch("https://<api-base-url>/v2.0/identityprovider/configure", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "<your-api-token>"
  },
  body: JSON.stringify({
    idpType: "saml",
    idpIssuer: "https://app.onelogin.com/saml/metadata/<id>",                                      // Issuer URL from the OneLogin SSO tab
    idpLoginEndpoint: "https://<subdomain>.onelogin.com/trust/saml2/http-post/sso/<id>",           // SAML 2.0 Endpoint (HTTP) from the OneLogin SSO tab
    idpCertificate: "<ONELOGIN_X509_CERTIFICATE>",                                                 // X.509 Certificate from the OneLogin SSO tab, base64-encoded on a single line
    idpLogoutEndpoint: "https://<subdomain>.onelogin.com/trust/saml2/http-redirect/slo/<id>"       // SLO Endpoint from the OneLogin SSO tab (optional)
  })
});
```

```
import requests

response = requests.post(
    "https://<api-base-url>/v2.0/identityprovider/configure",
    headers={
        "Content-Type": "application/json",
        "X-API-Key": "<your-api-token>"
    },
    json={
        "idpType": "saml",
        "idpIssuer": "https://app.onelogin.com/saml/metadata/<id>",                                      # Issuer URL from the OneLogin SSO tab
        "idpLoginEndpoint": "https://<subdomain>.onelogin.com/trust/saml2/http-post/sso/<id>",           # SAML 2.0 Endpoint (HTTP) from the OneLogin SSO tab
        "idpCertificate": "<ONELOGIN_X509_CERTIFICATE>",                                                 # X.509 Certificate from the OneLogin SSO tab, base64-encoded on a single line
        "idpLogoutEndpoint": "https://<subdomain>.onelogin.com/trust/saml2/http-redirect/slo/<id>"       # SLO Endpoint from the OneLogin SSO tab (optional)
    }
)
```

A successful request returns a confirmation that the identity provider configuration has been saved. The Cognigy.AI login page now displays a **Log in with SSO** button for users in your organization.

## [​](https://docs.cognigy.com/ai/administer/installation/identity-providers\#test-the-sso-login)  Test the SSO Login

1. On the Cognigy.AI login page, enter the email address of a user assigned to the IdP app and click **Log in with SSO**. Cognigy.AI redirects you to the IdP and prompts you for your IdP credentials. After authentication, the IdP redirects back to Cognigy.AI and logs you in.
2. Click the user icon in the lower-left corner and select **Logout**.
3. Enter your email address again and click **Log in with SSO**. This time, you are logged in directly without re-entering your IdP credentials.

## [​](https://docs.cognigy.com/ai/administer/installation/identity-providers\#more-information)  More Information

- [Single Sign-on with SAML 2.0](https://docs.cognigy.com/ai/administer/installation/single-sign-on-saml2)
- [Auth0: OpenID Connect Protocol](https://auth0.com/docs/authenticate/protocols/openid-connect-protocol)
- [Auth0: SAML Configuration](https://auth0.com/docs/authenticate/protocols/saml/saml-configuration)
- [Microsoft Entra ID: Enable SAML single sign-on for an enterprise application](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso)
- [Google Workspace: Set up your own custom SAML app](https://knowledge.workspace.google.com/admin/apps/set-up-your-own-custom-saml-app)
- [Okta: Create SAML app integrations](https://help.okta.com/oie/en-us/content/topics/apps/apps_app_integration_wizard_saml.htm)
- [OneLogin: SAML Custom Connector (Advanced)](https://support.onelogin.com/kb/4266907/saml-custom-connector-advanced)

Last modified onJune 9, 2026

[Previous\\
\\
Single Sign-on using SAML 2.0](https://docs.cognigy.com/ai/administer/installation/single-sign-on-saml2)

Ctrl+I

ChatVoice

Click the call button to start talking.

Cognigy AssistantReady to talk

Connecting…

Powered by [Cognigy.AI](/content/site-root.html)

### Cookie Consent

We use cookies to recognize your repeated visits and preferences, as well as to measure the effectiveness of our documentation and whether users find what they're searching for.

With your consent, you're helping us make our documentation better.
To find out more about the cookies we use, see our
[Privacy Policy](/content/privacy-policy/index.html).

Accept

';
 cachedClickBlockingCode = css + js;
 return cachedClickBlockingCode;
 }

// Helper: Inject click-blocking code into iframe
 function injectClickBlocking(iframeDoc) {
 if (!iframeDoc \|\| !iframeDoc.head) return false;

try {
 const style = iframeDoc.createElement('style');
 style.textContent = 'a,button,input,select,textarea,\[onclick\],\[role="button"\],input\[type="button"\],input\[type="submit"\],\[href\],\[tabindex\]:not(\[tabindex="-1"\]){pointer-events:none!important;cursor:default!important}a:hover,button:hover{cursor:default!important;opacity:0.7!important}';
 iframeDoc.head.appendChild(style);

const script = iframeDoc.createElement('script');
 script.textContent = '(function(){var preventClick=function(e){e.preventDefault();e.stopPropagation();e.stopImmediatePropagation();return false;};document.addEventListener("click",preventClick,true);document.addEventListener("mousedown",preventClick,true);document.addEventListener("mouseup",preventClick,true);document.addEventListener("touchstart",preventClick,true);document.addEventListener("touchend",preventClick,true);document.addEventListener("contextmenu",preventClick,true);window.addEventListener("beforeunload",function(e){e.preventDefault();e.returnValue="";return "";},true);try{Object.defineProperty(window,"location",{value:{href:"#",replace:function(){},assign:function(){}},writable:false,configurable:false});}catch(e){}var originalPushState=history.pushState;history.pushState=function(){return false;};var originalReplaceState=history.replaceState;history.replaceState=function(){return false;};var originalOpen=window.open;window.open=function(){return null;};var allElements=document.querySelectorAll("\*");for(var i=0;i 0 \|\| replacedViewers.length > 0) {
 const currentUrl = window.location.href;
 if (!processedUrls.has(currentUrl)) {
 processedUrls.add(currentUrl);
 lastUrl = currentUrl;
 }
 return;
 }

const currentUrl = window.location.href;
 if (currentUrl === lastUrl && lastUrl !== null && processedUrls.has(currentUrl)) {
 return;
 }

// Optimized: Use cached viewer query
 const viewers = getUninitializedViewers();

if (viewers.length === 0) {
 if (periodicCheckInterval) {
 clearInterval(periodicCheckInterval);
 periodicCheckInterval = null;
 }
 return;
 }

// Final safety check
 if (viewers.length > 0) {
 if (currentUrl === lastUrl && lastUrl !== null && processedUrls.has(currentUrl)) {
 viewers.forEach(function(viewer) {
 viewer.setAttribute('data-initialized', 'true');
 });
 return;
 }

if (currentUrl === lastUrl && lastUrl !== null) {
 if (existingContainers.length > 0) {
 processedUrls.add(currentUrl);
 viewers.forEach(function(viewer) {
 viewer.setAttribute('data-initialized', 'true');
 });
 return;
 }
 }
 }

isInitializing = true;
 let processedAny = false;

// Optimized: Process viewers in batch
 viewers.forEach(function(viewer) {
 if (processedElements.has(viewer) \|\| viewer.hasAttribute('data-initialized')) {
 return;
 }

if (viewer.closest('.single-page-viewer-container')) {
 return;
 }

if (!viewer.parentNode) {
 return;
 }

const isInContentArea = contentArea === document.body \|\| contentArea.contains(viewer);
 if (!isInContentArea) {
 return;
 }

const src = viewer.getAttribute('data-src');
 const hint = viewer.getAttribute('data-hint') \|\| '';
 const defaultZoom = parseFloat(viewer.getAttribute('data-zoom')) \|\| DEFAULT\_ZOOM;
 const dataHeight = viewer.getAttribute('data-height');
 const height = dataHeight ? parseFloat(dataHeight) : null;

if (!src) {
 // Don't set isInitializing = false here - it affects all viewers in the loop
 return;
 }

processedElements.add(viewer);
 viewer.setAttribute('data-initialized', 'true');

let zoom = defaultZoom;

// Optimized: Use document fragment for DOM construction
 const fragment = document.createDocumentFragment();
 const container = document.createElement('div');
 container.className = 'single-page-viewer-container';

const wrapper = document.createElement('div');
 wrapper.className = 'single-page-viewer-wrapper';

const controlsBar = document.createElement('div');
 controlsBar.className = 'single-page-viewer-controls';

if (hint) {
 const hintDiv = document.createElement('div');
 hintDiv.className = 'single-page-viewer-hint';
 hintDiv.innerHTML = '' \+ hint + '';
 controlsBar.appendChild(hintDiv);
 }

const iframeWrapper = document.createElement('div');
 iframeWrapper.className = 'single-page-viewer-iframe-wrapper';
 iframeWrapper.\_scrollHandlerAdded = false;

// Optimized: Get height without temporary DOM manipulation
 const baseHeightFromCSS = height \|\| NORMAL\_HEIGHT;

const scaleDiv = document.createElement('div');
 scaleDiv.className = 'single-page-viewer-scale';
 const initialHeight = baseHeightFromCSS;
 scaleDiv.style.cssText = 'transform: scale(' + zoom + '); transform-origin: top left; width: ' + (100 / zoom) + '%; height: ' + initialHeight + 'px; transition: transform 0.2s ease;';

const iframe = document.createElement('iframe');
 let iframeSrc = src;
 if (iframeSrc && !iframeSrc.startsWith('http') && !iframeSrc.startsWith('//')) {
 if (!iframeSrc.startsWith('/')) {
 iframeSrc = '/' + iframeSrc;
 }
 }

iframe.title = 'Single Page Viewer';
 iframe.className = 'single-page-viewer-iframe';
 iframe.style.width = '100%';
 iframe.style.height = initialHeight + 'px';
 iframe.loading = 'lazy';
 iframe.setAttribute('scrolling', 'no');
 iframe.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups allow-modals');

const clickBlocker = document.createElement('div');
 clickBlocker.className = 'single-page-viewer-click-blocker';

if (iframeSrc.endsWith('.html') && !iframeSrc.startsWith('http')) {
 fetch(iframeSrc)
 .then(function(response) {
 return response.text().then(function(htmlContent) {
 if (htmlContent.includes('Page Not Found') \|\|
 (htmlContent.includes('\_\_next') && htmlContent.includes('mintlify') && !htmlContent.includes('Page saved with SingleFile'))) {
 throw new Error('Received 404 page instead of HTML file.');
 }
 const blockingCode = getClickBlockingCode();
 if (htmlContent.includes('')) {
 htmlContent = htmlContent.replace('', blockingCode + '');
 } else if (htmlContent.includes('')) {
 htmlContent = htmlContent.replace('', '' + blockingCode);
 } else {
 if (htmlContent.includes('')) {
 htmlContent = htmlContent.replace('', '' + blockingCode + '');
 } else {
 htmlContent = blockingCode + htmlContent;
 }
 }
 iframe.srcdoc = htmlContent;
 });
 });
 } else {
 iframe.src = iframeSrc;
 }

iframe.addEventListener('load', function() {
 setTimeout(function() {
 updateIframeDimensions(iframeWrapper, scaleDiv, iframe, zoom);
 }, 100);

try {
 const iframeDoc = iframe.contentDocument \|\| iframe.contentWindow.document;
 injectClickBlocking(iframeDoc);
 } catch (e) {
 // Cross-origin iframe - cannot block clicks
 }
 }, { once: true });

iframe.addEventListener('error', function() {
 // Iframe failed to load - error handling is silent
 }, { once: true });

scaleDiv.appendChild(iframe);
 iframeWrapper.appendChild(scaleDiv);
 if (!iframeSrc.endsWith('.html') \|\| iframeSrc.startsWith('http')) {
 iframeWrapper.appendChild(clickBlocker);
 }

if (hint) {
 wrapper.appendChild(controlsBar);
 }
 wrapper.appendChild(iframeWrapper);
 container.appendChild(wrapper);
 fragment.appendChild(container);

try {
 if (viewer.parentNode) {
 if (viewer === contentArea \|\| viewer.id === 'content-area') {
 isInitializing = false;
 return;
 }

const viewerId = 'viewer-' + Date.now() + '-' + Math.random().toString(36).slice(2, 11);
 viewer.id = viewerId;
 viewer.setAttribute('data-viewer-id', viewerId);
 container.setAttribute('data-viewer-id', viewerId);

// Optimized: Single DOM insertion using fragment
 if (viewer.nextSibling) {
 viewer.parentNode.insertBefore(fragment, viewer.nextSibling);
 } else {
 viewer.parentNode.appendChild(fragment);
 }

// Batch style updates
 Object.assign(viewer.style, {
 display: 'none',
 visibility: 'hidden',
 position: 'absolute',
 width: '1px',
 height: '1px',
 overflow: 'hidden',
 opacity: '0',
 pointerEvents: 'none',
 margin: '0',
 padding: '0'
 });

viewer.setAttribute('data-initialized', 'true');
 viewer.setAttribute('data-viewer-replaced', 'true');

processedAny = true;
 invalidateQueryCache();

requestAnimationFrame(function() {
 updateIframeDimensions(iframeWrapper, scaleDiv, iframe, zoom);
 });
 }
 } catch (e) {
 isInitializing = false;
 return;
 }
 });

if (processedAny) {
 const currentUrl = window.location.href;
 processedUrls.add(currentUrl);
 lastUrl = currentUrl;
 invalidateQueryCache();
 }

isInitializing = false;
 }

// Wait for content area to be available
 function waitForContentArea(callback, maxAttempts, attempt) {
 attempt = attempt \|\| 0;
 maxAttempts = maxAttempts \|\| 20;

const contentArea = document.querySelector('#content-area') \|\| document.querySelector('.mdx-content');

if (contentArea && document.contains(contentArea)) {
 cachedContentArea = contentArea;
 callback();
 } else if (attempt < maxAttempts) {
 setTimeout(function() {
 waitForContentArea(callback, maxAttempts, attempt + 1);
 }, 500);
 } else {
 cachedContentArea = document.body;
 callback();
 }
 }

// Optimized: Initialize with better state management
 function initialize() {
 const currentUrl = window.location.href;
 if (lastUrl !== currentUrl && lastUrl !== null) {
 lastUrl = currentUrl;
 processedUrls.clear();
 invalidateQueryCache();
 }

if (typeof window !== 'undefined') {
 window.\_\_lastFullUrl = window.location.href;
 }

if (lastThemeClass === null && document.documentElement) {
 lastThemeClass = document.documentElement.className;
 }

if (!themeObserver && document.documentElement) {
 themeObserver = new MutationObserver(function(mutations) {
 for (let i = 0; i < mutations.length; i++) {
 const mutation = mutations\[i\];
 if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
 const currentThemeClass = document.documentElement.className;
 if (lastThemeClass !== null && lastThemeClass !== currentThemeClass) {
 themeToggleInProgress = true;

// Optimized: Lock containers synchronously
 const contentArea = getContentArea();
 if (contentArea) {
 const containers = getContainers(true);
 containers.forEach(function(container) {
 if (container.getAttribute('data-position-locked') !== 'true') {
 const rect = container.getBoundingClientRect();
 Object.assign(container.style, {
 position: 'fixed',
 top: rect.top + 'px',
 left: rect.left + 'px',
 width: rect.width + 'px',
 zIndex: '9999',
 margin: '0'
 });
 container.setAttribute('data-position-locked', 'true');
 containerPositions.set(container, {
 top: rect.top,
 left: rect.left,
 width: rect.width,
 height: rect.height
 });
 }
 });
 }

let repositionAttempts = 0;
 const maxRepositionAttempts = 30;

const repositionInterval = setInterval(function() {
 repositionAttempts++;
 repositionContainersAfterThemeToggleCore(); // Use core function for immediate repositioning
 if (repositionAttempts >= maxRepositionAttempts) {
 clearInterval(repositionInterval);
 }
 }, 100);

setTimeout(function() {
 clearInterval(repositionInterval);
 themeToggleInProgress = false;
 repositionContainersAfterThemeToggleCore(); // Use core function for final repositioning
 unlockContainers();
 }, 3000);
 }
 lastThemeClass = currentThemeClass;
 }
 }
 });

themeObserver.observe(document.documentElement, {
 attributes: true,
 attributeFilter: \['class'\]
 });
 }

if (typeof MutationObserver !== 'undefined') {
 setupObserver();
 }

waitForContentArea(function() {
 setTimeout(function() {
 initSinglePageViewers();
 setTimeout(function() {
 const remaining = getUninitializedViewers(true);
 if (remaining.length > 0) {
 initSinglePageViewers();
 }
 }, INIT\_DELAY);
 }, INIT\_DELAY);
 });
 }

// Optimized: Lock/unlock containers
 function lockContainersInPlace() {
 const contentArea = getContentArea();
 if (!contentArea) return;

const containers = getContainers(true);
 containerPositions.clear();

requestAnimationFrame(function() {
 containers.forEach(function(container) {
 if (container.getAttribute('data-position-locked') !== 'true') {
 const rect = container.getBoundingClientRect();
 Object.assign(container.style, {
 position: 'fixed',
 top: rect.top + 'px',
 left: rect.left + 'px',
 width: rect.width + 'px',
 zIndex: '9999',
 margin: '0'
 });
 container.setAttribute('data-position-locked', 'true');
 containerPositions.set(container, {
 top: rect.top,
 left: rect.left,
 width: rect.width,
 height: rect.height
 });
 }
 });
 });
 }

function unlockContainers() {
 const contentArea = getContentArea();
 if (!contentArea) return;

const containers = Array.from(
 contentArea.querySelectorAll('.single-page-viewer-container\[data-position-locked="true"\]')
 );

containers.forEach(function(container) {
 Object.assign(container.style, {
 position: '',
 top: '',
 left: '',
 width: '',
 zIndex: '',
 margin: ''
 });
 container.removeAttribute('data-position-locked');
 // Clean up container position from Map to prevent memory leak
 containerPositions.delete(container);
 });

containerPositions.clear();
 }

// Optimized: Reposition containers with better DOM operations
 // Core repositioning function (not debounced for immediate use)
 function repositionContainersAfterThemeToggleCore() {
 const contentArea = getContentArea();
 if (!contentArea) return;

const containers = getContainers(true);

containers.forEach(function(container) {
 const viewerId = container.getAttribute('data-viewer-id');
 if (!viewerId) return;

let viewer = document.getElementById(viewerId);

if (!viewer) {
 const iframe = container.querySelector('iframe');
 if (iframe && iframe.src) {
 const allViewers = contentArea.querySelectorAll('\[data-single-page-viewer\]');
 for (let i = 0; i < allViewers.length; i++) {
 const v = allViewers\[i\];
 if (v.getAttribute('data-src') === iframe.src) {
 viewer = v;
 viewer.id = viewerId;
 viewer.setAttribute('data-viewer-id', viewerId);
 Object.assign(viewer.style, {
 display: 'none',
 visibility: 'hidden',
 position: 'absolute',
 width: '1px',
 height: '1px',
 overflow: 'hidden',
 opacity: '0',
 pointerEvents: 'none',
 margin: '0',
 padding: '0'
 });
 viewer.setAttribute('data-initialized', 'true');
 viewer.setAttribute('data-viewer-replaced', 'true');
 break;
 }
 }
 }
 }

if (viewer && viewer.parentNode) {
 if (container.getAttribute('data-position-locked') === 'true') {
 unlockContainers();
 }

const viewerIndex = Array.from(viewer.parentNode.children).indexOf(viewer);
 const containerIndex = Array.from(viewer.parentNode.children).indexOf(container);

if (containerIndex !== viewerIndex + 1) {
 // CRITICAL: Check if container is actually a child before removing
 if (container.parentNode && container.parentNode.contains(container)) {
 try {
 container.parentNode.removeChild(container);
 } catch (e) {
 return; // Skip repositioning if removal failed
 }
 }
 if (viewer.nextSibling) {
 viewer.parentNode.insertBefore(container, viewer.nextSibling);
 } else {
 viewer.parentNode.appendChild(container);
 }
 } else if (container.parentNode !== viewer.parentNode) {
 // CRITICAL: Check if container is actually a child before removing
 if (container.parentNode && container.parentNode.contains(container)) {
 try {
 container.parentNode.removeChild(container);
 } catch (e) {
 return; // Skip repositioning if removal failed
 }
 }
 if (viewer.nextSibling) {
 viewer.parentNode.insertBefore(container, viewer.nextSibling);
 } else {
 viewer.parentNode.appendChild(container);
 }
 }
 }
 });

invalidateQueryCache();
 }

// Debounced version for non-critical repositioning
 const repositionContainersAfterThemeToggle = debounce(repositionContainersAfterThemeToggleCore, REPOSITION\_DEBOUNCE);

// Optimized: Observer setup with better filtering
 let observer = null;
 let containerPositionObserver = null;
 let fallbackObserver = null; // Track fallback observer for cleanup

function setupContainerPositionObserver() {
 if (typeof MutationObserver === 'undefined') return;

const contentArea = getContentArea();
 if (!contentArea \|\| !document.contains(contentArea)) {
 setTimeout(setupContainerPositionObserver, 500);
 return;
 }

if (containerPositionObserver) {
 containerPositionObserver.disconnect();
 }

containerPositionObserver = new MutationObserver(function(mutations) {
 if (themeToggleInProgress) {
 // Use core function (not debounced) for immediate repositioning during theme toggle
 requestAnimationFrame(repositionContainersAfterThemeToggleCore);
 return;
 }

let needsReposition = false;
 for (let i = 0; i < mutations.length && !needsReposition; i++) {
 if (mutations\[i\].type === 'childList') {
 needsReposition = true;
 }
 }

if (needsReposition) {
 clearTimeout(containerPositionObserver.\_timeout);
 containerPositionObserver.\_timeout = setTimeout(repositionContainersAfterThemeToggle, REPOSITION\_DEBOUNCE);
 }
 });

containerPositionObserver.observe(contentArea, {
 childList: true,
 subtree: true,
 attributes: false,
 characterData: false
 });

containerPositionObserver.\_timeout = null;
 }

// Optimized: Main observer with better early exits
 function setupObserver() {
 if (typeof MutationObserver === 'undefined') return;

const contentArea = getContentArea();
 if (!contentArea \|\| !document.contains(contentArea)) {
 setTimeout(setupObserver, 500);
 return;
 }

if (contentArea === document.documentElement \|\| contentArea === document.body) {
 return;
 }

if (observer) {
 const currentObserved = observer.\_observedElement;
 if (currentObserved === contentArea && document.contains(contentArea)) {
 return;
 }
 if (currentObserved) {
 observer.disconnect();
 }
 observer = null;
 }

observer = new MutationObserver(function(mutations) {
 if (themeToggleInProgress) return;

let hasNewViewer = false;
 for (let i = 0; i < mutations.length && !hasNewViewer; i++) {
 const mutation = mutations\[i\];
 if (mutation.addedNodes && mutation.addedNodes.length > 0) {
 for (let j = 0; j < mutation.addedNodes.length && !hasNewViewer; j++) {
 const node = mutation.addedNodes\[j\];
 if (node.nodeType === 1 &&
 node.hasAttribute &&
 node.hasAttribute('data-single-page-viewer') &&
 !node.hasAttribute('data-initialized') &&
 !node.hasAttribute('data-viewer-replaced')) {
 hasNewViewer = true;
 }
 }
 }
 }

if (hasNewViewer) {
 // Use core function for immediate repositioning when new viewer detected
 repositionContainersAfterThemeToggleCore();
 setTimeout(repositionContainersAfterThemeToggleCore, 10);
 setTimeout(repositionContainersAfterThemeToggleCore, 50);
 setTimeout(repositionContainersAfterThemeToggleCore, 200);
 }

clearTimeout(observerTimeout);
 observerTimeout = setTimeout(function() {
 if (themeToggleInProgress) return;

let hasNewViewer = false;
 for (let i = 0; i < mutations.length && !hasNewViewer; i++) {
 const mutation = mutations\[i\];

if (mutation.target === document.documentElement \|\| mutation.target === document.body) {
 continue;
 }

if (mutation.type === 'attributes' &&
 mutation.attributeName === 'class' &&
 mutation.target === document.documentElement) {
 continue;
 }

if (mutation.type === 'attributes' && mutation.attributeName === 'data-initialized') {
 const target = mutation.target;
 if (target && target.hasAttribute &&
 target.hasAttribute('data-single-page-viewer') &&
 !target.hasAttribute('data-initialized')) {
 hasNewViewer = true;
 }
 }

if (mutation.addedNodes && mutation.addedNodes.length > 0) {
 for (let j = 0; j < mutation.addedNodes.length && !hasNewViewer; j++) {
 const node = mutation.addedNodes\[j\];
 if (node.nodeType === 1 &&
 node.hasAttribute &&
 node.hasAttribute('data-single-page-viewer') &&
 !node.hasAttribute('data-initialized')) {
 hasNewViewer = true;
 }
 }
 }
 }

if (hasNewViewer) {
 invalidateQueryCache();
 initSinglePageViewers();
 }
 }, OBSERVER\_DEBOUNCE);
 });

observer.observe(contentArea, {
 childList: true,
 subtree: true,
 attributes: true,
 attributeFilter: \['data-initialized'\],
 characterData: false
 });

observer.\_observedElement = contentArea;
 setupContainerPositionObserver();
 }

function start() {
 setupObserver();
 initialize();
 }

function checkAndInitialize() {
 if (isInitializing) return;

const currentUrl = window.location.href;
 if (currentUrl === lastUrl && lastUrl !== null) {
 return;
 }

const contentArea = document.querySelector('#content-area') \|\| document.querySelector('.mdx-content');
 if (contentArea) {
 const viewers = getUninitializedViewers(true);
 if (viewers.length > 0) {
 cachedContentArea = contentArea;
 setupObserver();
 initialize();
 }
 }
 }

if (document.readyState === 'loading') {
 document.addEventListener('DOMContentLoaded', start);
 } else {
 setTimeout(start, 100);
 }

if (typeof window !== 'undefined' && window.next) {
 let initialLoadAttempts = 0;
 const maxInitialAttempts = 4;
 const attemptDelays = \[200, 500, 1000, 2000\];
 const initialUrl = window.location.href;

attemptDelays.forEach(function(delay) {
 setTimeout(function() {
 if (initialLoadAttempts < maxInitialAttempts) {
 initialLoadAttempts++;
 if (window.location.href === initialUrl) {
 checkAndInitialize();
 }
 }
 }, delay);
 });
 }

window.addEventListener('popstate', function(e) {
 const currentUrl = window.location.href;
 if (currentUrl !== lastUrl) {
 handleNavigation();
 }
 });

if (typeof window !== 'undefined') {
 if (window.next && window.next.router && window.next.router.events) {
 window.next.router.events.on('routeChangeComplete', function(url) {
 lastUrl = window.location.href;
 isInitializing = false;
 pendingInitCall = false;
 if (navigationTimeout) {
 clearTimeout(navigationTimeout);
 navigationTimeout = null;
 }
 invalidateContentAreaCache();
 invalidateQueryCache();
 setTimeout(function() {
 setupObserver();
 initialize();
 }, 300);
 });

window.next.router.events.on('routeChangeStart', function(url) {
 isInitializing = false;
 pendingInitCall = false;
 });
 }

if (!window.next \|\| !window.next.router) {
 const originalPushState = history.pushState;
 const originalReplaceState = history.replaceState;

history.pushState = function() {
 originalPushState.apply(history, arguments);
 setTimeout(function() {
 if (window.location.href !== lastUrl) {
 handleNavigation();
 }
 }, 0);
 };

history.replaceState = function() {
 originalReplaceState.apply(history, arguments);
 setTimeout(function() {
 if (window.location.href !== lastUrl) {
 handleNavigation();
 }
 }, 0);
 };
 }
 }

document.addEventListener('visibilitychange', function() {
 if (!document.hidden) {
 isInitializing = false;
 startPeriodicCheck();
 if (!pendingInitCall) {
 pendingInitCall = true;
 setTimeout(function() {
 pendingInitCall = false;
 initSinglePageViewers();
 }, INIT\_DELAY / 2);
 }
 }
 });

function startPeriodicCheck() {
 if (periodicCheckInterval) return;

periodicCheckInterval = setInterval(function() {
 const uninitialized = getUninitializedViewers(true);
 if (uninitialized.length === 0) {
 clearInterval(periodicCheckInterval);
 periodicCheckInterval = null;
 } else if (!isInitializing) {
 initSinglePageViewers();
 }
 }, 2000);
 }

setTimeout(startPeriodicCheck, INIT\_DELAY \* 2);

window.\_\_singlePageViewerInit = function() {
 const currentUrl = window.location.href;
 if (currentUrl === lastUrl) {
 return;
 }

isInitializing = false;
 pendingInitCall = false;
 lastUrl = currentUrl;
 invalidateContentAreaCache();
 invalidateQueryCache();
 setupObserver();
 initialize();
 };

window.\_\_singlePageViewerCheck = function() {
 invalidateQueryCache();
 initSinglePageViewers();
 };
})();

// Optimized: Second IIFE for navigation handling
(function() {
 'use strict';

let lastPathname = window.location.pathname;
 let lastInitializedPathname = window.location.pathname;

function checkAndInit() {
 const currentPathname = window.location.pathname;
 if (currentPathname === lastInitializedPathname) {
 return;
 }

lastInitializedPathname = currentPathname;
 if (typeof window !== 'undefined') {
 window.\_\_lastFullUrl = window.location.href;
 }

if (window.\_\_singlePageViewerInit) {
 window.\_\_singlePageViewerInit();
 }
 }

function runInit() {
 if (window.\_\_singlePageViewerInit) {
 setTimeout(checkAndInit, 100);
 } else {
 let attempts = 0;
 const maxAttempts = 50;
 const checkInterval = setInterval(function() {
 attempts++;
 if (window.\_\_singlePageViewerInit) {
 clearInterval(checkInterval);
 setTimeout(checkAndInit, 100);
 } else if (attempts >= maxAttempts) {
 clearInterval(checkInterval);
 }
 }, 100);
 }
 }

if (document.readyState === 'loading') {
 document.addEventListener('DOMContentLoaded', runInit);
 } else {
 setTimeout(runInit, 100);
 }

if (typeof window !== 'undefined' && window.next && window.next.router && window.next.router.events) {
 window.next.router.events.on('routeChangeComplete', function(url) {
 lastPathname = window.location.pathname;
 setTimeout(checkAndInit, 300);
 });
 }

setInterval(function() {
 const currentPathname = window.location.pathname;
 if (currentPathname !== lastPathname) {
 lastPathname = currentPathname;
 setTimeout(checkAndInit, 300);
 }
 }, 500);

if (typeof MutationObserver !== 'undefined') {
 let fallbackObserverTimeout = null;
 // Store in outer scope for cleanup tracking
 fallbackObserver = new MutationObserver(function(mutations) {
 if (fallbackObserverTimeout) {
 clearTimeout(fallbackObserverTimeout);
 }
 fallbackObserverTimeout = setTimeout(function() {
 const contentArea = document.querySelector('#content-area');
 if (contentArea) {
 const uninitialized = contentArea.querySelectorAll(
 '\[data-single-page-viewer\]:not(\[data-initialized\]):not(.single-page-viewer-container \[data-single-page-viewer\])'
 );
 if (uninitialized.length > 0) {
 const currentPathname = window.location.pathname;
 if (currentPathname !== lastInitializedPathname) {
 setTimeout(checkAndInit, 200);
 }
 }
 }
 }, 500);
 });

if (document.body) {
 fallbackObserver.observe(document.body, { childList: true, subtree: true });
 } else {
 document.addEventListener('DOMContentLoaded', function() {
 if (document.body) {
 fallbackObserver.observe(document.body, { childList: true, subtree: true });
 }
 });
 }
 }
})();
