What you’ll need
Three values from the dashboard:| Value | Format | Where to find it | Where it goes |
|---|---|---|---|
| Org ID | UUID | Setup > Install (in the snippet) | Frontend, in the snippet |
| Widget key | ab_live_... | Setup > Install (Widget key card) | Frontend, in the snippet — publishable, safe to expose in the browser |
| Identity secret | ha_secret_... | Settings > Security | Server only — used to sign JWTs for identity verification |
pk_live_ — designed for client-side use. The identity secret is like a Stripe sk_live_ — never expose it.
Your widget key
The widget key (ab_live_...) is your publishable credential. It goes in the apiKey field of HaloAgents.init() and in the Authorization header if you call the REST API from your backend today.
- Safe in HTML — anyone can read it from your page source; that is expected.
- Copy anytime — open Setup > Install in the dashboard. The full key is shown there with a copy button.
- Regenerate — use Regenerate widget key on that page if the key is compromised. Your live snippet stops working until you redeploy with the new key.
- Legacy keys — workspaces created before April 2026 may have a key we cannot display. Regenerate once to get a copyable key.
user_id, enable Identity Verification under Settings > Security.
The snippet
Paste this before the closing</body> tag on every page where you want the widget:
Default behavior is quiet
The default config keeps the chat panel closed on page load. Users with unread messages see a small dot on the launcher; the panel only opens when they tap. Same as Intercom. You can drop the snippet on every page (marketing, app, auth flows) and it won’t cover a Sign Up or checkout button. If you want louder behavior on logged-in pages, opt in via theui config:
* matches any chars, ? matches one).
The SDK prints a one-time
console.warn if init() runs on an auth route with autoOpenUnseen: true and no manualOnPaths covering it. The warning is local to the browser session and has no production effect.Identifying the user
As soon as you know who the user is (after login), callidentify() so the AI can personalize and your team can see them in the inbox:
Async loading
To avoid blocking page rendering, use theasync attribute. Wait for window.HaloAgents before calling init() — onload fires when the file finishes downloading, not when the global is registered.
next/script, React effects, or any dynamic script injection.
WordPress
Add the snippet to your theme’sfooter.php or use a plugin that allows custom scripts:
Pinning a specific version
Thelatest/ URL is the right default for most sites: every customer automatically gets bug fixes and security updates the moment we publish them. For sites with strict change-management or security-review requirements, you can pin to a specific version instead.
Versioned URLs
Every published SDK version is also served atcdn.haloagents.ai/sdk/<version>/:
Subresource Integrity (SRI)
For the strongest guarantee, combine version pinning with anintegrity attribute. The browser will refuse to execute the script if the bytes don’t match the hash, which protects you against CDN compromise even if our infrastructure is breached.
https://api.haloagents.ai/api/sdk/sri:
SRI requires the
crossorigin="anonymous" attribute so the browser is willing to compare bytes across origins. Without it the browser refuses to enforce the integrity check.Which to use?
| Need | Recommended |
|---|---|
| Get bug fixes and security updates automatically | latest/ (default) |
| Strict change-management; vetted builds only | <version>/ pinned |
| Vetted builds + cryptographic tamper protection | <version>/ + integrity |
Content Security Policy (CSP)
If your site uses a Content Security Policy, Halo needs permission to connect to the API and load the script.Chat only
If you’re only using chat (no voice, no Live Help), add:Chat + Live Help (streaming avatar)
Live Help uses HeyGen and LiveKit infrastructure, so add all of:Examples
In a<meta> tag (chat only):
<meta> tag (chat + Live Help):
Diagnosing CSP issues
- Open DevTools (F12 or Cmd+Opt+I)
- Go to Console
- Look for red errors mentioning “Content Security Policy” or “connect-src”
- Add the missing domains
Most sites don’t use CSP at all. If you don’t have one configured, you don’t need to add anything.
Origin allow-list (optional)
By default the widget loads on any domain. If you want to lock it down to a specific list of sites, turn on Allowed Domains under Setup → Install in the dashboard.Origin header doesn’t match an entry is rejected with a 403. Per-user impersonation is a separate concern handled by Identity Verification. Allowed Domains is purely an embedding control.
Local development
The browser setsOrigin: http://localhost:3000 for code running on your dev server, which won’t match a production domain entry. Add the loopback hostname you actually use to your allow-list:
http://127.0.0.1:3000 if you added 127.0.0.1, or http://localhost:3000 if you added localhost. Same model as Intercom’s Trusted Domains.
Wildcards must be scoped to a registrable name.
*.example.com is fine, but *.com and *.co.uk are rejected on save.Microphone permissions (voice features)
If your agent uses voice input, Halo needs access to the user’s microphone viagetUserMedia. Most sites work out of the box, but two configurations can block access.
Permissions-Policy header
If your server sendsPermissions-Policy (or legacy Feature-Policy) restricting microphone, voice fails with “Permissions policy violation: microphone is not allowed in this document”.
Fix:
microphone=() (fully blocked), update it.
Embedding in an iframe
If you load the widget inside an<iframe>, add the allow="microphone" attribute:
Permissions-Policy header must also allow microphone=(self).
Where to go next
Identify Users
Tell Halo who the user is and what company they belong to.
Send Context
Push structured data about the user’s current state.
Customize the Widget
Hide the trigger, open programmatically, theme, and use UI highlighting.
Methods Reference
Every method available on the HaloAgents instance.