@convai/web-widget
v0.1.3
Published
Two-line script-tag embed for the Convai chat widget. A <convai-widget> custom element with a closed shadow root and a lazily loaded runtime.
Readme
@convai/web-widget
Add a Convai character to any website with one custom element and one script tag.
Quickstart
Paste this, replace two values, and you have a working widget. It puts your API key in the page, which is fine on your own machine and not fine in production — step two moves it to your server.
<convai-widget character-id="YOUR_CHARACTER_ID" api-key="YOUR_API_KEY"></convai-widget>
<script src="https://cdn.jsdelivr.net/npm/@convai/[email protected]/v1.js" async></script>A launcher bubble appears in the bottom-right corner. Click it: the runtime downloads, the panel opens, and you can talk to your character by text or by voice.
React
The script tag goes in your HTML shell; the element is ordinary JSX.
<!-- index.html -->
<script src="https://cdn.jsdelivr.net/npm/@convai/[email protected]/v1.js" async></script><convai-widget character-id={CHARACTER_ID} api-key={API_KEY} />In Next.js, use next/script with strategy="afterInteractive" — it injects a
classic script tag, which is what the loader needs.
Do not
importthis package into an app bundle. The loader derives the runtime chunk's URL from its own<script src>, so a bundled import (or a<script type="module">) leaves it with nothing to derive from: the bubble paints and then fails on click withcould not resolve the runtime URL. Load it from a script tag. The npm package exists so you can self-hostv1.jsandruntime.jsfrom your own origin.
Before you ship
api-key is visible to anyone who views source, never expires, and is scoped
to your whole account — the widget logs a one-time warning saying so. Replace
it with token-endpoint, a single route you host whose entire job is to relay
one call:
app.post('/api/convai-token', async (req, res) => {
const upstream = await fetch('https://api.convai.com/user/connect', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'CONVAI-API-KEY': process.env.CONVAI_API_KEY },
body: '{}',
})
res.status(upstream.status).json(await upstream.json())
})Then swap one attribute:
- <convai-widget character-id="YOUR_CHARACTER_ID" api-key="YOUR_API_KEY"></convai-widget>
+ <convai-widget character-id="YOUR_CHARACTER_ID" token-endpoint="/api/convai-token"></convai-widget>The widget mints on first engagement and reuses the token for about an hour, so
this runs once per hour of use, not once per conversation. token-endpoint
outranks api-key, so leaving both on during a migration is safe — but delete
the key anyway, it is still in your page source.
A third mode, connect-endpoint, proxies the full connect request for teams who
want to inspect or gate it server-side. All three are covered in the docs.
If your character has Long-Term Memory enabled, add end-user-id — the
connect request is rejected without it. Each distinct value consumes an account
resource, so read the guidance before pointing it at production traffic.
Why it is built this way
- The script tag costs 8 KB. It paints the launcher immediately and nothing else. The full SDK — around 230 KB gzipped — is fetched only when a visitor actually engages, so a page nobody talks to pays almost nothing.
- Your CSS and the widget's cannot collide. Everything renders inside a closed shadow root, so the host page cannot reach in and the widget cannot leak out. Theming happens through eight documented custom properties.
- Your API key stays on your server once you move to
token-endpoint.
Documentation
Authentication in depth with working Express, Next.js and Cloudflare Worker
recipes; the complete attribute and event reference; a React and Next.js usage
guide; theming and ::part() hooks; CSP requirements; and guidance on
end-user-id and Long-Term Memory.
Versioning
0.1.3 is a stable release: npm install @convai/web-widget and
jsDelivr's unversioned URL both resolve it. Pin the exact version anyway for
reproducible deploys —
<script src="https://cdn.jsdelivr.net/npm/@convai/[email protected]/v1.js" async></script>npm install @convai/[email protected] # only needed to self-host the two filesThis package is early, and it bundles a prerelease of @convai/web-sdk. The
bundle is self-contained, so you install nothing from that — but expect the
surface to move before 1.0.
Browser support
Any browser with custom elements and shadow DOM: Chrome, Edge, Firefox, and Safari 16.4+. The widget needs microphone access for voice mode; text chat works without it.
