npm & React
@qafka/web isn’t on the public npm registry yet — contact Qafka for access. If you just need the widget on a site, the CDN snippet works today without any of this.
@qafka/web is a framework-agnostic createQafka() bootstrap, plus an optional React component built on top of it. Use this instead of the CDN snippet when your site already has a build step and signed-in users — a web app, SaaS dashboard, or portal.
Install
npm install @qafka/webreact is an optional peer dependency — only required if you import @qafka/web/react. The framework-agnostic entry point never pulls React in.
Allowed domains
Like the CDN snippet, a session only starts from an origin on the project’s registered Websites (and the key’s own website restriction, if it sets one). A key created through website onboarding is locked to that site’s domain, so for a web app you’ll usually create a separate Web key on the API Keys page (the number of keys per project depends on your plan) after registering your app’s domain (including localhost/staging, with scheme and port, e.g. http://localhost:3000) on the Websites page. See Web SDK Overview › Allowed domains and API Key Security.
Framework-agnostic
import { createQafka } from '@qafka/web'
const qafka = createQafka({
publishableKey: 'qafka_pk_...',
mode: 'floating', // or 'inline' with a `container`
})
// Later:
qafka.sendMessage('hello')
qafka.update({ endUserId: 'user_123' })
qafka.destroy()React
This is the exact shape the dashboard’s onboarding flow generates for a signed-in web app:
import { Qafka } from '@qafka/web/react';
<Qafka
publishableKey="qafka_pk_..."
endUserId={currentUser.id}
isAuthenticated
mode="floating"
/>isAuthenticated here reflects your own app’s sign-in state — it’s used for navigation screen filtering, not for identifying the visitor to the backend or unlocking tools: every web session is minted at the anonymous trust tier regardless. See Web SDK Overview › Visitor identity & tools on web.
<Qafka /> renders null — it owns an imperative createQafka instance behind the scenes and is safe to import in a server-rendered component (it never touches window/document outside its mount effect). Attach a ref to call instance methods directly:
import { Qafka, type QafkaHandle } from '@qafka/web/react'
import { useRef } from 'react'
function App() {
const ref = useRef<QafkaHandle>(null)
return (
<Qafka
ref={ref}
publishableKey="qafka_pk_..."
mode="floating"
onReady={() => console.log('Qafka mounted')}
/>
)
}Remount vs. update
Changing most props doesn’t remount the widget — the React wrapper applies the change to the live instance instead:
publishableKey,apiUrl,mode,containerchanging — destroys the current instance and creates a new one (these define the widget’s identity/connection).endUserId,endUserData,context,locale,isAuthenticated,contextDescriptionchanging — applied viaupdate(), no remount.- Every
on*callback exceptonStatusChange— a fresh inline arrow function every render never remounts the widget; only a callback going from present to absent (or back) triggers anupdate(). onStatusChangeis captured once, at mount — passing a new function on a later render doesn’t replace the handler.- Every other prop (
theme,assistantName,logoUrl,greetingMessage,placeholder,workletUrl,subProjectId, …) is read once, at mount.
The instance handle
Both createQafka() and <Qafka ref> return the same handle:
| Method | Description |
|---|---|
sendMessage(text) | Send a message as if the visitor typed it. |
open() / close() | Open or close the widget. |
openVoice() | Enter voice mode. |
setLoading(visible, message?) | Show/hide a loading state with an optional message. |
update(partial) | Re-apply a partial options update without a full remount. |
getStatus() | Current lifecycle status — see Options Reference below. |
destroy() | Unmount and release listeners. Idempotent. |
Next steps
- Options Reference — every
createQafka()option - Navigation —
isAuthenticated, screen filtering, and the same navigation model used on React Native - Voice — voice mode setup and web-only file upload
- WordPress — if you’d rather not write code at all