Publish
Publish an AI agent as a chat widget or an embedded conversation.
Open copy menu
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
Section titled “Before installation”- Test the most common customer questions in the Editor preview.
- Save your changes and publish the agent. A draft or paused agent will not respond on your site.
- Open Settings → Security. If domain restrictions are enabled, add every origin separately, for example
https://example.comandhttps://www.example.com.*.example.comdoes not include the apex domainexample.com.
Install the floating chat widget
Section titled “Install the floating chat widget”- Open the agent’s Editor.
- Select Install → Website chat widget.
- Copy the complete
<script>snippet. - Add it once to the shared site template, just before the closing
</body>tag. - 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 .
Leave the snippet off checkout pages that embed a payment form, so the payment page runs only the scripts the payment needs.
Astro sites
Section titled “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:
---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
Section titled “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:
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
Section titled “Identify a signed-in visitor”Create a short-lived HS256 JWT on your server and pass only the finished token to the browser:
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 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
Section titled “Embed the conversation in page content”- Select Install → Embedded chat.
- Copy the complete
<iframe>element. - Add it where the conversation should appear.
- 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
Section titled “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
Section titled “Trusted Types”If your CSP has a trusted-types or require-trusted-types-for directive, make these changes:
- If your CSP has a
trusted-typesdirective, add the namesvelte-trusted-htmlto 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. - If your page requires Trusted Types (
require-trusted-types-for 'script'), allow the widget’s two URLs in your page’s default policy, and adddefaultto thetrusted-typesdirective too if you have one. The installation code andaihio-loader.jsset the script URL as a plain string, which a Trusted Types page accepts only through the default policy.
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 . It needs only frame-src https://app.aihio.ai, because the conversation runs in its own document.
Prepare an accessibility audit
Section titled “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
Section titled “Verify the installation”- Open the published page in a private browser window.
- Confirm that the chat widget or embedded conversation appears and answers a test message.
- Test both mobile and desktop widths.
- Test accepted and rejected analytics consent if you pass consent to the widget.
- If you identify visitors, confirm in Settings → Security that Aihio has received a valid token before enabling enforcement.
If the conversation does not appear
Section titled “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 .
- A loading request fails: use the browser Network panel to confirm that
aihio-loader.jsand 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-heightvalue.
To remove the installation, delete the <script> or <iframe> element you added and publish the site again.
Pause or reactivate
Section titled “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.