# Publish

URL: https://aihio.ai/en/help/ai-agent/publish\
Description: Publish an AI agent as a chat widget or an embedded conversation.

You can publish an AI agent as a floating chat widget or as a conversation
placed in the page content. Always copy the code for this agent from the
Editor's **Install** menu. It already contains the correct public identifier,
so you do not need to edit it manually.

| Embed method            | Choose this when                                        | Note                                                                               |
| ----------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| **Website chat widget** | You want a floating launcher across the site            | Supports Widget API commands, analytics consent, and signed-in user identification |
| **Embedded chat**       | You want the chat window to be a fixed part of one page | Does not show a floating launcher or support host-page Widget API commands         |
| **WordPress**           | Your site runs on WordPress                             | The official plugin installs the widget without copying code                       |

## Before installation

1. Test the most common customer questions in the Editor preview.
2. Save your changes and publish the agent. A draft or paused agent will not respond on your site.
3. Open **Settings → Security**. If domain restrictions are enabled, add every origin separately, for example `https://example.com` and `https://www.example.com`. `*.example.com` does not include the apex domain `example.com`.

## Install the floating chat widget

1. Open the agent's **Editor**.
2. Select **Install → Website chat widget**.
3. Copy the complete `<script>` snippet.
4. Add it once to the shared site template, just before the closing `</body>` tag.
5. Publish the site change.

Most publishing systems provide a site-wide Footer or Custom Code field. On
WordPress, you can also use the [official Aihio Chatbot
plugin](/en/help/ai-agent/wordpress-plugin).

Leave the snippet off checkout pages that embed a payment form, so the payment
page runs only the scripts the payment needs.

### Astro sites

Create a component such as `src/components/AihioWidget.astro` and paste the
code copied from the Editor into it. Change only the opening `<script>` tag to
`<script is:inline>` so Astro does not bundle or move the public bootstrap.

Import the component into the shared layout and render it once before the
closing `</body>` tag:

```astro
---
import AihioWidget from '../components/AihioWidget.astro';
---

<html lang="en">
  <body>
    <slot />
    <AihioWidget />
  </body>
</html>
```

Never add the chatbot secret to an Astro component or a `PUBLIC_` environment
variable. The embed's `chatbotId` is a public identifier; the identity
verification secret belongs only on your server.

## Pass analytics consent

Chat remains available without analytics consent. Pass behavioral analytics
permission to the widget only after the visitor accepts it in your consent
manager:

```javascript
AihioWidget('consent', {
  analytics: hasAnalyticsConsent,
});
```

Replace `hasAnalyticsConsent` with the boolean from your consent manager and
call the command whenever the choice changes. Unknown or rejected consent maps
to `false`. Browser Do Not Track also disables widget analytics when the host
passes `true`.

## Identify a signed-in visitor

Create a short-lived `HS256` JWT on your server and pass only the finished
token to the browser:

```javascript
AihioWidget('identify', {
  token: serverSignedIdentityToken,
});
```

Call `AihioWidget('resetUser')` on sign-out so the next person using the same
device cannot see the previous visitor's conversation history. See the
[identity verification guide](/en/help/ai-agent/identity-verification) for
server examples, supported claims, and the safe rollout order. Never sign the
token in the browser or expose the secret in embed code.

## Embed the conversation in page content

1. Select **Install → Embedded chat**.
2. Copy the complete `<iframe>` element.
3. Add it where the conversation should appear.
4. Adjust the surrounding region's height. The default code uses a minimum height of 600 pixels.

An iframe works well on a contact or support page. Choose the script embed when
you need the floating launcher, the `identify` command, analytics consent, or
other Widget API commands.

## Content Security Policy

If your site sends a Content Security Policy (CSP), the browser loads only the
sources it allows. The chat widget runs in your page's own document, so allow
these sources. If your installation code loads `aihio-loader.js` from
`https://aihio.ai/widget/`, first copy the new code from the **Install** menu.

| Directive     | Add                                                                  | Used for                                                       |
| ------------- | -------------------------------------------------------------------- | -------------------------------------------------------------- |
| `script-src`  | `https://app.aihio.ai` or the page nonce                             | The installation code, `aihio-loader.js` and `aihio-widget.js` |
| `connect-src` | `https://app.aihio.ai`                                               | Settings, messages and streamed answers                        |
| `img-src`     | `https://negsyvjjuqqjhlsxuyzc.supabase.co` and `https://db.aihio.ai` | The logo and avatar you upload to Aihio                        |
| `media-src`   | `https://app.aihio.ai`                                               | The new-message sound                                          |
| `style-src`   | `'unsafe-inline'`                                                    | The widget's component styles                                  |
| `frame-src`   | `https://app.aihio.ai`                                               | The embedded chat only                                         |

The inline installation code also needs a nonce or a hash. When you add your
page nonce to the installation code's `<script>` element, the code passes it to
`aihio-loader.js`, which passes it on to the widget. Your `script-src` can then
allow scripts by nonce alone, also together with `'strict-dynamic'`. Do not add
`'unsafe-inline'` to `script-src` for the widget.

`style-src` still needs `'unsafe-inline'`, because the widget adds its
component styles as `<style>` elements without a nonce. A nonce alone is not
yet enough for styles. If the same directive also has a nonce or a hash, the
browser ignores `'unsafe-inline'`, so remove them from your style sources or
use the embedded chat.

### Trusted Types

If your CSP has a `trusted-types` or `require-trusted-types-for` directive,
make these changes:

1. If your CSP has a `trusted-types` directive, add the name
   `svelte-trusted-html` to it. The widget creates a policy with this name, and
   the name does not change. If your site runs Svelte 5 itself, also add
   `'allow-duplicates'` to the same directive, because the name is then
   already taken.
2. If your page requires Trusted Types (`require-trusted-types-for 'script'`),
   allow the widget's two URLs in your page's default policy, and add `default`
   to the `trusted-types` directive too if you have one. The installation code
   and `aihio-loader.js` set the script URL as a plain string, which a Trusted
   Types page accepts only through the default policy.

```javascript
trustedTypes.createPolicy('default', {
  createScriptURL(url) {
    const allowed = [
      'https://app.aihio.ai/widget/aihio-loader.js',
      'https://app.aihio.ai/widget/aihio-widget.js',
    ];
    if (allowed.includes(url)) return url;
    throw new TypeError('Script URL not allowed');
  },
});
```

If your page already has a default policy, add these two URLs to it. The
browser console error tells you what is missing:

| Error message                                           | Fix                                                         |
| ------------------------------------------------------- | ----------------------------------------------------------- |
| `Policy "svelte-trusted-html" disallowed`               | Add `svelte-trusted-html` to the `trusted-types` directive. |
| `Policy with name "svelte-trusted-html" already exists` | Add `'allow-duplicates'`.                                   |
| `This document requires 'TrustedScriptURL' assignment`  | Add the default policy.                                     |

If you cannot change your page's Trusted Types policy, use the
[embedded chat](#embed-the-conversation-in-page-content). It needs only
`frame-src https://app.aihio.ai`, because the conversation runs in its own
document.

## Prepare an accessibility audit

The chat widget runs in a closed Shadow DOM, so accessibility checkers cannot
see inside it. Open it for the audit by adding the option `isolation: 'open'`
to the snippet's `init` call. In an older embed that uses the `<script>` tag's
data attributes, add the attribute `data-isolation="open"` to the tag.

Restore the original code after the audit. In open mode, session-replay and
analytics scripts on the host page can read the chat text.

## Verify the installation

1. Open the published page in a private browser window.
2. Confirm that the chat widget or embedded conversation appears and answers a test message.
3. Test both mobile and desktop widths.
4. Test accepted and rejected analytics consent if you pass consent to the widget.
5. If you identify visitors, confirm in **Settings → Security** that Aihio has received a valid token before enabling enforcement.

## If the conversation does not appear

- **The browser reports a domain error:** add the exact origin shown in the address bar to the allowed domains. Add preview and production domains separately.
- **The browser console reports a CSP error:** check which sources to allow in [Content Security Policy](#content-security-policy).
- **A loading request fails:** use the browser Network panel to confirm that `aihio-loader.js` and the chatbot configuration request return successful responses.
- **The code works on only some pages:** move the script to the shared layout and ensure it is added only once.
- **The iframe is too short:** set a height on its containing element or adjust the iframe's `min-height` value.

To remove the installation, delete the `<script>` or `<iframe>` element you
added and publish the site again.

## Pause or reactivate

Open the agent status menu in the top bar and select **Pause** to stop answering temporarily. Confirm the status changes to **Paused** and test the effect on your website.

To resume, select **Reactivate** and verify with a test message that the agent answers again. If activation is blocked, check for a ready knowledge source and review the visible error.

Pausing does not remove the website installation code. Remove the code separately if you do not want the conversation interface to load at all. Changing status also does not restore earlier instructions or a previous configuration.
