HomeAdd a widgetany website

AI chat · any website

Add an AI chat widget to any website

A chat agent that answers from your own content, floating in the corner of every page on Any website — with 200 conversations a month included on the $19 plan, and a person able to take over at any point.

Free plan, no card. Paid plans start at $19 a month.

Why do it this way on any website

One tag in the layout every page shares and the launcher is on your whole site. The single rule that matters: it has to be inside <body>, immediately before the closing tag. The chat loader attaches itself to document.body the moment it runs, with no retry — so in <head>, where document.body does not exist yet, it throws and nothing appears, silently. The form and calendar embeds are forgiving about this; the chat one is not.

See it working

There is a live one on this page already. The chat button in the bottom corner is a Sorraia AI chat agent — ours, answering from this site’s own content — installed exactly the way the steps above describe. Open it and ask it something.

How to add an AI chat widget to any website

A launcher pins itself to a corner of the screen wherever inside the body the tag sits, so it goes once into the layout every page shares.

  1. In Sorraia, add the website and verify it — a DNS TXT record, or a meta tag in your homepage’s <head>. Verification is what lets you attach a widget to that site, so it comes before there is anything to paste.

  2. Save the agent, then copy the snippet from the Embed code box in the right-hand panel of the chat builder. (Chat has no install wizard — the box is the whole thing.)

  3. Copy the snippet from Sorraia.

  4. Paste it into the one template every page inherits — a Hugo baseof.html, a Jekyll default layout, an Astro Layout.astro, a Next.js app/layout.tsx — immediately before the closing </body> tag.

  5. Deploy. Do not paste it into pages one at a time.

  6. Load any page and confirm the launcher appears in the corner. Anywhere inside <body> works; where you put it does not change where it lands.

Before </body>, and not in <head>

For the chat launcher this is a hard requirement rather than a preference. The chat loader appends its root to document.body synchronously, with no readyState guard and no retry — in <head> document.body is still null, so it throws and the launcher never appears, silently. The form and calendar loaders are the tolerant ones: they mount synchronously, retry on DOMContentLoaded, then fall back to a MutationObserver that gives up after 30 seconds. Before </body> is right for all of them; for chat it is the only thing that works.

What you get

A chat agent that answers from your own content, floating in the corner of every page on any website — with 200 conversations a month included on the $19 plan, and a person able to take over at any point.

200 conversations a month on the $19 plan

The monthly allowance is 25 conversations on Free, 200 on Starter at $19/month, 1,000 on Growth, 5,000 on Business and 20,000 on Enterprise. A conversation counts once when it starts, not per message, and the counter resets at the start of each UTC month.

Past the cap it keeps answering, at a price you can see

On any paid plan the agent carries on past its allowance at $15 per 100 additional conversations — or part of 100, so one conversation over the line is one $15 pack, and we would rather say that than let you discover it on an invoice. Every account also carries a ceiling on how many packs it will buy, defaulting to ten ($150 of extra exposure), and at the ceiling the widget behaves exactly as it does with overage switched off. Free does not run an overage; it stops at 25.

It says it is an AI, always

Every conversation opens with a line naming the agent as your business’s AI assistant and noting that a human can take over. That line is not a setting — the widget will not render without it. When someone from your team does take over, the status changes to say so.

It answers from your site, not from the open internet

The agent is grounded in your own content, which is why it can answer a question about your pricing or your opening hours and will not invent a policy you never wrote. If a calendar is wired up it can also take a booking mid-conversation — and it only claims it can book when one actually is.

More detail in the Help Center: The AI chat agent · Embedding on your website

Things worth knowing about any website

  • Astro bundles any <script src> that carries no other attribute — which is exactly the shape of the snippet. Add the is:inline directive so Astro leaves it alone.
  • Hugo strips raw HTML out of Markdown unless markup.goldmark.renderer.unsafe is true. Put the tag in a layout or partial instead of in a content file.
  • In React, dangerouslySetInnerHTML never executes a script — that is the HTML spec, not a React bug, and it fails silently. Render the placeholder <div> in JSX and load the script separately. In Next.js use next/script: lazyOnload in app/layout.tsx for a floating launcher, the default afterInteractive on the page itself for an inline widget.
  • If your site sends a Content-Security-Policy, the directive that catches people out is style-src. The loader builds its stylesheet at runtime — createElement("style"), set textContent, append to <head> — which counts as an inline style, and it sets no nonce anywhere. So it needs 'unsafe-inline' there or the widget loads and renders completely unstyled. A nonce-only style-src breaks it, and 'strict-dynamic' does not help because that is a script-src feature. You also need the Sorraia API origin under connect-src and the host printed in your snippet under script-src.
  • Because the widget renders into your DOM rather than an iframe, your own CSS reaches it — an aggressive global rule on form, input or button can restyle it, and an ancestor with overflow:hidden can clip it. That is the trade for having no sandbox: no isolation bugs, but no isolation either.

Questions

What happens when I hit the monthly conversation limit?

On a paid plan, nothing visible: the agent keeps answering and the extra conversations bill at $15 per 100 — rounded up to the next pack — capped by a per-account pack ceiling you control, ten by default. On Free it stops starting new conversations for the rest of the month, and the widget degrades rather than vanishing: the panel still opens, the disclosure line corrects itself to say the assistant is offline, the message box is disabled, and your WhatsApp and email handoffs are surfaced instead. A conversation already in progress is never cut off. The visitor is never shown your plan, your usage, or the reason.

Will visitors know they are talking to an AI?

Yes, by design. The disclosure line is always rendered — it names your business, says “AI assistant”, and tells the visitor a human can step in — and it cannot be switched off in the builder. If a teammate takes the conversation over, the widget stops describing itself as the AI and says the team is live.

Can a person take over a conversation?

Yes, and the visitor is told both times. Pick up any live conversation from the Conversations page and the widget posts “A team member has joined the conversation.” and switches its status from “AI assistant · replies instantly” to “Live · with the team”. Hand it back and it says so. If whoever took over walks away, the conversation returns to the AI on its own after about ten idle minutes rather than leaving the visitor waiting on someone who has gone.

Do I need to install anything?

No. There is no plugin, no package and no build step — the whole install is one script tag. It works on a static site, a hand-written page, a Rails or Laravel template, an SSG like Hugo or Eleventy, or a React app, because it is plain HTML from the browser’s point of view.

Will it work behind a Content-Security-Policy?

Yes, with three directives. Allow the host printed in your own snippet under script-src, allow the Sorraia API origin under connect-src, and allow 'unsafe-inline' under style-src — the loader builds its stylesheet as an injected style element and sets no nonce, so a nonce-only style-src leaves the widget rendered but completely unstyled. If your widget uses a Google webfont, also allow fonts.googleapis.com under style-src and fonts.gstatic.com under font-src.

Add an AI chat widget to any website

Build it in Sorraia, paste one line into your site, and change it later without touching the embed again.