Skip to content

Live chat widget

Add the Vocenya website live chat with one script tag, control it with the JavaScript API, and answer chats from your own systems.

The Vocenya live chat puts your AI receptionist on your website: it answers visitors, captures leads and hands the chat to a person when it should. Installing it is one script tag with your business's public site key, found in the portal under Live chat → Install.

The instructions below are the same ones Vocenya gives to AI site builders such as Lovable, Bolt, v0 and Cursor. Each business also gets its own copy with its key filled in, at /chat/{site key}/install.md, and the generic version is at https://vocenya.com/developers/chat-install.md. The portal's install page can copy a ready-made prompt or open it in ChatGPT or Claude for you.

What to add

Add this script tag once, so it loads on every page, just before the closing </body> tag (or the framework equivalent below):

HTML
<script src="https://vocenya.com/api/chat/widget.js" data-key="pk_YOUR_SITE_KEY" async></script>

Replace pk_YOUR_SITE_KEY with the site key from the Vocenya portal (Live chat → Install). Each business has its own key.

The chat bubble then appears in the corner of every page. Nothing else is required.

Rules

  • Load the script once, site-wide, in the shared layout or template. Not per page and not twice.
  • Load it from https://vocenya.com/api/chat/widget.js exactly. Do not download, bundle, self-host, inline, minify or proxy the script: it is updated on our side.
  • Do not change, remove or invent the data-key value.
  • Keep async and do not add type="module".
  • It is browser-only. Keep it out of server-only code paths (server components' logic, API routes, SSR data loaders, edge functions). Never call window.Vocenya during server rendering; call it only in the browser, from event handlers or effects.
  • Do not install an npm package for it: there is none. Do not add a chat component of your own.
  • If the site sends a Content Security Policy, add the sources below rather than loosening the policy any further.

Where it goes, by framework

Plain HTML or any server-rendered template

Paste the tag just before </body> in the template every page shares (footer include, base layout, theme.liquid, etc.).

Next.js (App Router)

In the root layout app/layout.tsx, use next/script with strategy="afterInteractive", inside <body>:

TypeScript
import Script from 'next/script';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://vocenya.com/api/chat/widget.js" data-key="pk_YOUR_SITE_KEY" strategy="afterInteractive" />
      </body>
    </html>
  );
}

Pages Router: put the same <Script> in pages/_app.tsx.

Vite + React (Lovable, Bolt, v0 exports, Replit and most AI-built React apps)

Add the tag to index.html at the project root, just before </body>. Not inside a React component.

Vue (Vite) and Nuxt

Vue with Vite: add the tag to index.html before </body>. Nuxt: add it with useHead in app.vue (or app.head.script in nuxt.config.ts):

TypeScript
useHead({ script: [{ src: 'https://vocenya.com/api/chat/widget.js', 'data-key': 'pk_YOUR_SITE_KEY', async: true, tagPosition: 'bodyClose' }] });

SvelteKit

Add the tag to src/app.html, just before </body>.

Astro

Add the tag to the base layout every page uses (for example src/layouts/Layout.astro), just before </body>, with is:inline so Astro does not bundle it:

HTML
<script is:inline src="https://vocenya.com/api/chat/widget.js" data-key="pk_YOUR_SITE_KEY" async></script>

Remix and React Router (framework mode)

In app/root.tsx, inside <body> next to <Scripts />:

TypeScript
<script src="https://vocenya.com/api/chat/widget.js" data-key="pk_YOUR_SITE_KEY" async></script>

Webflow, Framer, Wix, Squarespace and other site builders

Use the site-wide custom code setting, not a page embed:

  • Webflow: Site settings → Custom code → Footer code. Publish.
  • Framer: Site settings → General → Custom code → End of tag. Publish.
  • Wix: Settings → Custom code → Add custom code, All pages, Load once, Body - end.
  • Squarespace: Settings → Advanced → Code injection → Footer.
  • WordPress: use the Vocenya Chat plugin from the Vocenya portal, or the theme footer.

Content Security Policy

Only if the site sets a Content-Security-Policy (header or meta tag), add these sources to the existing directives:

Text
script-src https://vocenya.com
connect-src https://vocenya.com wss://ws.vocenya.com
img-src https://vocenya.com
frame-src https://vocenya.com

connect-src covers the chat API and the live-reply websocket. frame-src is only needed if you also embed the hosted chat page in an iframe.

Optional: the JavaScript API

Only if asked. To call the chat before the script has loaded, add this stub above the script tag; calls are queued and replayed:

HTML
<script>window.Vocenya = window.Vocenya || function () { (window.Vocenya.q = window.Vocenya.q || []).push(arguments); };</script>
  • Vocenya('open'), Vocenya('close'), Vocenya('toggle'): control the chat window.
  • Vocenya('identify', { name, email, phone }): prefill a signed-in visitor so the team sees who they are.
  • Vocenya('on', 'message' | 'open' | 'close' | 'lead', callback) and Vocenya('off', event, callback): listen for chat events.

A "Chat with us" button:

HTML
<button type="button" onclick="window.Vocenya && window.Vocenya('open')">Chat with us</button>

Identify a logged-in user in React (browser only):

TypeScript
useEffect(() => {
  if (user) {
    window.Vocenya?.('identify', { name: user.name, email: user.email });
  }
}, [user]);

In TypeScript, declare it once: declare global { interface Window { Vocenya?: (...args: unknown[]) => void } }.

Allowed domains

The chat only runs on the domains listed under Live chat → Install in the Vocenya portal. Make sure the site's live domain is on that list; preview or staging domains (for example *.lovable.app or *.vercel.app) must be added too if the chat should work there.

Check it worked

  1. Publish or deploy the site.
  2. Open the live site in a private window: a chat bubble appears in the corner. Click it and send a test message.
  3. No bubble? Open the browser console: look for a blocked script or connection (Content Security Policy) or a domain that is not allowed.
  4. Within a few minutes the Vocenya portal shows the chat as "Installed".

When you are done

Tell the owner which file you changed and confirm the script tag is unchanged. Docs: https://vocenya.com/developers/chat-install.md

Answer chats from your own systems

The chat is also part of the API, so a bot or your help desk can take part:

  1. Subscribe a webhook endpoint to chat.message.created (scope chats:read).
  2. Reply with POST /chats/{chat}/messages (scope chats:write). Replies show in the visitor's widget straight away, from "Team". Replying to a chat the AI is answering takes it over, so the AI stops answering.
  3. Skip messages with via_api: true: they are your own replies.
  4. Close the chat with POST /chats/{chat}/close when you are done.

Replies are limited to 30 a minute per key. See the Chats reference and the live chat events.

Channels: website and WhatsApp

Chats come from two channels, and the API treats them the same way. Every chat and every chat.* webhook payload has a channel:

  • web: the website widget. page_url is the page the visitor was on, and contact_address is null.
  • whatsapp: a customer messaging the business's WhatsApp number. contact_address is the customer's number in E.164 (for example +15550102030), and page_url is null.

WhatsApp only allows free-form replies within 24 hours of the customer's last message. reply_window_open on a WhatsApp chat tells you whether that window is open. Outside it, POST /chats/{chat}/messages is refused with 422 and code whatsapp_window_closed, plus a hint. Follow up with an approved template from the Vocenya inbox instead. Templates only go to customers who opted in to WhatsApp messages and have not replied STOP.

WhatsApp is not available to HIPAA-mode accounts.