Embed the Chat Widget
Add the AgentStack chat bubble to any website — plain HTML or a framework — and avoid the two mistakes that make it silently fail to appear.
The chat widget is two <script> tags. The hard part is not the snippet. The
hard part is where you place it, and how you configure the allowed domains. If
you get both steps right, the bubble shows up everywhere.
The snippet
Copy the snippet from your agent's Deploy → Chat Widget page. This page already includes your agent ID.
<!-- AgentStack Widget -->
<script>
window.agentstack=new Proxy({_q:[]},{get(t,p){
if(p==='_q')return t._q;return(...a)=>t._q.push([p,...a]);
}});
</script>
<script src="https://www.agentstack.build/embed.js" data-agent-id="YOUR_AGENT_ID" async></script>Replace YOUR_AGENT_ID with the ID shown on the Deploy page.
If you build agents through the REST API, use the right one of the two ids. POST /agents returns id and publicId. Every REST call takes id. The data-agent-id attribute takes publicId. The Deploy page always shows publicId, so a snippet copied from the dashboard is already correct.
Let your coding agent install it
If you use Claude Code, Cursor, or another AI coding agent, paste the prompt below. The prompt tells the agent how to detect your framework and place the snippet in the one file that wraps every page. Most installs fail because the snippet ends up in a file that does not render on the public site.
Install the AgentStack chat widget on this website.
The widget is these two script tags (keep them together, in this order):
<script>
window.agentstack=new Proxy({_q:[]},{get(t,p){
if(p==='_q')return t._q;return(...a)=>t._q.push([p,...a]);
}});
</script>
<script src="https://www.agentstack.build/embed.js" data-agent-id="YOUR_AGENT_ID" async></script>
CRITICAL — place them in the file that wraps EVERY page that real visitors load,
not just any layout file. First detect the stack, then use the matching target:
- Plain HTML / static site: add both tags just before </body> in every page
(or the shared template/partial/include if the site uses one).
- Next.js — detect the router FIRST. A project can contain BOTH src/app/ and
src/pages/; what matters is which one renders the route visitors hit (often "/").
• If the homepage is served by the Pages Router (a pages/index.* or
src/pages/index.* file exists, OR the rendered page exposes
window.__NEXT_DATA__): put the widget in pages/_app.tsx (or src/pages/_app.tsx),
rendered via next/script with strategy="lazyOnload".
• If the homepage is served by the App Router (app/page.* or src/app/page.*
exists and there is NO pages/index.*): put it in app/layout.tsx inside
<body>, via next/script with strategy="lazyOnload".
• Do NOT assume App Router just because a src/app/layout.tsx exists — if there
is no app/page.* and the routes live under pages/, that layout never renders.
- React (Vite/CRA, no SSR): add the two raw tags to index.html before </body>.
Do not convert them to JSX in a component.
- Vue / Nuxt: Nuxt → add to app.vue or nuxt.config (app.head script). Plain Vue
→ index.html before </body>.
- SvelteKit: src/app.html before %sveltekit.body% or just before </body>.
- Astro: the base layout in src/layouts/ used by every page, before </body>.
- WordPress / other CMS: the theme footer template, or a "scripts in footer"
setting / plugin.
When the framework provides a script primitive (next/script, Nuxt useHead, etc.),
prefer it over a raw tag and load the script lazily/after-interactive — the widget
is non-critical and should not block render.
After installing, verify (see the checklist in the AgentStack embed docs):
1. Load the public site and confirm window.agentstack is defined (not undefined).
2. Confirm a network request to https://www.agentstack.build/embed.js returns 200.
3. Confirm the chat bubble renders, and clicking it opens a working chat panel.
Report which framework you detected and which file you edited.Swap YOUR_AGENT_ID in the prompt for your real agent ID before you send it.
Domain protection: do not use *. wildcards
On the Deploy page, you can restrict which domains can embed your agent. This
is where fresh installs most often fail. The matcher supports exact
hostnames and automatic subdomain coverage. The matcher does not
support *. glob wildcards.
| You want to allow | Enter this | Do not enter |
|---|---|---|
example.com and all its subdomains (www., app., …) | example.com | *.example.com |
Only app.example.com | app.example.com | — |
| Local development | localhost | — |
Rules:
- A bare domain already covers its subdomains.
example.commatchesexample.com,www.example.com,app.example.com, and so on. You do not need a separate wildcard line. - Do not enter
*.example.com. The dashboard refuses to save it. Over the REST API it is stored as plain text and never matches a hostname, so no domain can open the chat panel. - Enter the host only. Do not add
https://. Do not add awww.prefix, a port, or a trailing path. The dashboard refuses to savehttps://example.com/. Over the REST API it is stored as plain text and never matches.example.commatches. - Leave the field empty to allow all domains. If you want to restrict embedding, enter a domain in the field.
Verify the install
- Open your public site. Use the real domain, not a preview URL. Domain protection blocks hosts that are not on the allow list.
- Open DevTools → Console. Run
window.agentstack. If the result isundefined, the snippet is not on the page. The snippet is in the wrong file. See the framework list above. - Open DevTools → Network.
embed.jsmust return 200. - The bubble appears in the bottom-right corner by default. Click it. The chat
panel loads. When a bubble opens to an empty panel or an error panel, this
usually means a domain-protection mismatch. See the
*.wildcard mistake above.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
No bubble appears, and window.agentstack is undefined | The snippet is in a file that does not render on the public site (for example, a Next.js App Router layout when the site uses the Pages Router) | Move the snippet to the file that wraps every page |
No bubble appears, but window.agentstack is defined | The agent is not public, or the agent is geo-restricted | Make the agent public on the Deploy page. Check the geo settings. |
| The bubble appears, but the panel is empty or shows "not allowed on this domain" | Domain-protection mismatch, usually a *. wildcard or an entry with a https:// prefix | Use the bare hostname. Remove the *. and the scheme. |
| The widget works locally, but not in production | localhost is on the allow list, but the production domain is not | Add the bare production hostname |