Install the chat widget in one line of HTML.

One script tag. No framework. No backend changes on your side. Paste before </body> and a chat bubble appears in your brand color, wired to your VerboSync tenant.

One-line install
<script async src="https://YOUR-VERBOSYNC-HOST/api/widget/widget.js?t=YOUR_TENANT_ID"></script>

Replace the two placeholders, paste before </body>, and the bubble appears.

Copy & paste

<!-- VerboSync chat widget -->
<script
  async
  src="https://gateway-production-8b00.up.railway.app/api/widget/widget.js?t=00000000-0000-0000-0000-000000000000"
></script>

Two things to change:

PlaceholderWhat to putExample
host
https://gateway-…railway.app
Your VerboSync gateway URL — given to you by VerboSync https://gateway-production-8b00.up.railway.app or your custom domain
?t= Your VerboSync tenant ID (UUID) cc7dfcde-3f6e-4727-96d5-46fd57c83089

How it works (in 30 seconds)

  1. The browser loads widget.js from your VerboSync host. The script reads ?t= off its own <script src> to learn which tenant it belongs to.
  2. It calls GET /api/widget/config?tenant_id=… to fetch your branding (color, greeting, position, avatar).
  3. When a visitor clicks the bubble, it POSTs /api/widget/session to mint a short-lived JWT and opens a WebSocket at wss://…/ws/chat?token=….
  4. Messages flow over that WebSocket. Replies stream back into the panel.

The whole UI lives inside a closed Shadow DOM — its styles can't leak into your page and your CSS can't break the widget.

Where to find your tenant ID

  1. From your VerboSync admin — they can copy it from the operator console.
  2. From any /api/* request — browser devtools → Network → look at the X-Tenant-ID request header.
  3. Ask support if the operator console doesn't expose it yet.

The tenant ID is a public identifier, not a secret. It's safe to put in page HTML, source control, and analytics. Authentication happens server-side via the short-lived JWT session token.

Where to paste the tag

Site typeWhere to paste
Plain HTMLJust before </body>
WordPressAppearance → Theme File Editor → footer.php (before </body>) — or a plugin like Insert Headers and Footers
ShopifyOnline Store → Themes → Edit code → theme.liquid (before </body>)
WebflowProject Settings → Custom Code → Footer Code
SquarespaceSettings → Advanced → Code Injection → Footer
WixSite → Custom Code → add new → Place code in Body — end on All pages
Google Tag ManagerNew tag → Custom HTML → paste the snippet → trigger: All Pages
React / Next.js / Vite SPAAdd to your root HTML once (index.html or app/layout.tsx) — NOT per-route. See SPA section.

The tag has async, so it loads in parallel with your page and never blocks rendering.

SPA frameworks (React, Next.js, Vue)

Mount the script once at app shell level, not inside route components, so re-renders don't add the bubble multiple times.

Next.js (App Router)

// app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Script
          src="https://YOUR-HOST/api/widget/widget.js?t=YOUR_TENANT_ID"
          strategy="afterInteractive"
        />
      </body>
    </html>
  );
}

Next.js (Pages Router)

// pages/_app.tsx
import Script from "next/script";

export default function App({ Component, pageProps }) {
  return (
    <>
      <Component {...pageProps} />
      <Script
        src="https://YOUR-HOST/api/widget/widget.js?t=YOUR_TENANT_ID"
        strategy="afterInteractive"
      />
    </>
  );
}

Plain Vite / CRA / Vue / Svelte SPA

Put the <script> tag in index.html before </body> like a static-HTML site. Don't add it via useEffect or a component — once is enough.

Customizing the look

You do not configure the widget in code. All appearance settings live in the VerboSync operator console so non-developers can change them without redeploying your site:

SettingWhat it controlsDefault
Brand colorBubble background, header, send button, visitor messages#4F46E5
Greeting messageFirst message shown when the panel opensHi! How can we help you today?
Positionbottom-right or bottom-leftbottom-right
Avatar URLHeader avatar image (~36×36 px, any size accepted)Default icon
EnabledMaster kill switch — turn off without removing the script tagOn

Tell your VerboSync admin which knobs you want changed; they edit them in the operator console and the widget picks up the new config on next page load (cached ~1 hour by HTTP cache headers on widget.js).

Verifying the install

  1. Load any page where you pasted the tag.
  2. You should see a circular chat bubble in your brand color (bottom-right by default).
  3. Click it — the panel slides up with your greeting.
  4. Type a message and press Enter — it should appear on the right; the agent should "type…" and reply.

If nothing appears

What you seeLikely causeFix
No bubble at all, console silentScript tag missing/typo'd; widget.js returned 404Re-check <script src> and the host
Console: Missing tenant ID in script tag (?t=TENANT_ID)Forgot ?t=…Add it
Console: Failed to initialize widget … 404Tenant ID wrong, OR widget disabled, OR Chat SKU not activeVerify the ID; have your VerboSync admin check Settings → Widget + Billing → Chat
Console: 402 / EntitlementErrorChat add-on isn't on this tenantAdd the Chat SKU in the operator console
Bubble appears, but panel never opens / "trouble connecting"WebSocket blocked (corporate firewall, CSP)See CSP section
Bubble appears twiceTag included twice (e.g. both index.html and a React useEffect)Keep only one

Security model

ConcernAnswer
Is the tenant ID a secret?No. It's a public identifier, like a Stripe publishable key. Authentication happens via the short-lived JWT minted at /api/widget/session.
What authenticates the WebSocket?A per-session JWT (HS256, signed server-side) carried as ?token=. Encodes tenant_id, session_id, and an expiry.
Can someone else embed our widget on their site?Today, yes — origin whitelisting is on the roadmap. If you need it, ask support.
Cookies?None.
localStorage?None.
Fingerprinting?No client-side fingerprinting. The HTTP request reaches the VerboSync gateway, which sees the visitor's IP (standard for any HTTP call).
GDPR-friendly?Only collects what the visitor types and standard request metadata. Treat it like any other live-chat service in your privacy policy.

Style isolation: the widget mounts under a closed Shadow DOM. Your CSS cannot reach into it, and its CSS cannot leak into your site — so you cannot override widget styles from your CSS. Use the operator-console config knobs instead.

Content Security Policy (CSP)

If your site has a strict CSP, you need three allowances. Replace YOUR-HOST with your VerboSync gateway:

script-src   'self' https://YOUR-HOST;
connect-src  'self' https://YOUR-HOST wss://YOUR-HOST;
img-src      'self' data: https://YOUR-HOST;

If you use script-src 'strict-dynamic', the async script will still load (added to the DOM, not inline), but make sure your nonce/hash strategy isn't applied to third-party scripts. The widget uses Shadow DOM and does not need style-src 'unsafe-inline'.

Removing or disabling

  1. Toggle off in the operator console (Settings → Widget → Enabled). The script tag can stay; the widget will render nothing.
  2. Drop the Chat SKU — same effect, plus the WebSocket can't be opened even with a cached bundle.
  3. Remove the <script> tag from your site.

Option 1 is reversible without touching code — use it for maintenance windows.

Caching & versioning

widget.js is served with Cache-Control: public, max-age=3600 — visitors may cache it for an hour. Config (/api/widget/config) is not cached, so brand-color and greeting changes apply immediately. To force an update before the hour is up, version-bust the URL:

<script async src="https://YOUR-HOST/api/widget/widget.js?t=YOUR_TENANT_ID&v=2"></script>

Reference — what the widget calls

MethodURLPurpose
GET/api/widget/widget.js?t=TENANT_IDThe bundle
GET/api/widget/config?tenant_id=TENANT_IDBranding / enable flag
POST/api/widget/session (body: { tenant_id })Mints a short-lived JWT
WS/ws/chat?token=JWTBidirectional chat ({ type:"message"|"reply"|"ack", text })

All four are served by your VerboSync gateway. The widget never talks to anyone else — no third-party CDN, no analytics pings.

Install checklist

  • Got your tenant ID (UUID) and gateway host from VerboSync.
  • The Chat SKU is active on your VerboSync tenant.
  • Pasted the <script> tag before </body> on every page (or once at SPA shell level).
  • Reloaded a page — bubble appears in your brand color.
  • Clicked the bubble — greeting appears.
  • Sent a test message — got a reply.
  • Verified an operator can see the conversation in the operator console (Conversations inbox, channel = web).
  • If you have a CSP, added the three allowances above.
  • If your site has cookie/consent gating, decided whether the widget loads before or after consent.

FAQ

Can I embed the widget on multiple sites for the same tenant?
Yes — paste the same tag on as many sites as you like. Conversations from all of them land in one inbox.

Can different pages show different greetings?
Not today — greeting is per-tenant. Visitor-context APIs are on the roadmap; ask support.

Does the widget work on mobile?
Yes. The panel is responsive (max-width: calc(100vw - 32px)) and uses viewport-aware sizing.

Can I host widget.js from my own domain?
No — the bundle hard-codes the gateway origin it was served from for its config/session/WebSocket calls. Load it from your VerboSync host.

Will it slow down my site?
The script tag is async, so it doesn't block the parser. The bundle is small (single self-contained file, no framework) and the network calls only happen when a visitor opens the panel.

Developers