Chat
Chatlink
Chat is the New Instance customer conversation product: an embeddable widget that pairs an AI chatbot (answering from your knowledge base, around the clock) with live human chat (your agents, in the dashboard), plus native SDKs so the same conversations work inside your mobile apps.
How it workslink
- A visitor opens the widget on your site or app and talks to the AI assistant first; it answers from the knowledge you've configured.
- When the AI can't help - or the visitor asks - the conversation hands off to a human agent in Dashboard → Chat, honouring your routing rules and agent availability.
- Conversations are real-time both ways (server-sent events with WebSocket fallback), support file attachments, typing indicators and unread counts, and survive page reloads.
- Prompts are screened by the platform's AI-injection guard; manipulation attempts are rejected before they reach the model.
Integration surfaceslink
| Surface | How | Auth |
|---|---|---|
| Web | embed.js script tag or the NInstanceChat JavaScript API (below) | Publishable widget key - the bare key ID, safe in page source |
| Android / iOS / React Native / Flutter | Native chat SDKs (sub-pages below) with a ready-made chat UI | Same publishable widget key |
The widget key is deliberately secret-less: server-side it is clamped to chat operations only, so shipping it in client code exposes nothing else.
Two ways to identify the customerlink
- Anonymous. Ship the widget key alone. The visitor gets the pre-chat form and the conversation is anonymous.
- Authenticated. Your backend mints a short-lived chat identity token with
createCsCustomerTokenand hands it to the client. The token is the identity: the customer's details never have to be passed into the SDK, and a tampered client cannot claim to be somebody else.
Both use the same publishable key. See Authentication and identity for the token API, the SDK calls, and the diagnostic error codes; see Theming for how dashboard, local and built-in themes combine.
Configure your chat widgetlink
- Log in to the merchant dashboard
- Navigate to Dashboard → Org → Chat (
/dashboard/org/[orgId]/chat) - Configure your widget: appearance, AI chatbot, routing rules, agent availability
- Copy your Widget API Key - this is the key ID only (e.g.
sk_live_abc123), not thekeyId:secretform. The widget runs in a browser; the secret must never appear in client-side code.
Embed the widget via script tag (auto-init)link
Add this to your HTML <head> or just before </body>:
<script
src="https://widget.newinstance.cloud/embed.js"
data-api-key="sk_live_abc123"
data-theme="dark"
data-position="bottom-right"
></script>data attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
data-api-key | string (required) | - | Widget key ID (NOT the full secret) |
data-theme | dark | light | light |
data-position | bottom-right | bottom-left | bottom-right |
data-transport | sse | ws | inherited |
data-customer-name / -email / -id | string | - | Pre-fill customer identity |
data-auto-open | boolean | false | Open the panel on load |
data-gql-endpoint / data-widget-url | URL | derived | Self-host overrides for API endpoint and iframe origin |
Embed via JavaScript API (full control)link
<script src="https://widget.newinstance.cloud/embed.js"></script>
<script>
const widget = NInstanceChat.init({
apiKey: 'sk_live_abc123', // key ID only - never the secret
theme: 'dark',
position: 'bottom-right',
customerName: 'John',
customerEmail: 'john@example.com',
customerId: 'usr_123',
autoOpen: false,
callbacks: {
onAuth: (info) => console.log('Chat auth:', info.valid, info.status),
onOpen: () => console.log('Chat opened'),
onClose: () => console.log('Chat closed'),
},
});
// Programmatic control
widget.open();
widget.close();
widget.toggle();
widget.isOpen();
widget.updateConfig({ theme: 'light', customerName: 'Ada' });
widget.destroy();
// File attachments (before opening composer)
widget.attachFile(file);
widget.attachFiles([fileA, fileB]);
widget.removeAttachment(id);
widget.clearAttachments();
widget.getAttachments();
widget.openComposer();
</script>NInstanceChat.init(config) options
| Option | Type | Description |
|---|---|---|
apiKey | string (required) | Widget key ID |
theme | dark | light |
transport | sse | ws |
gqlEndpoint / widgetUrl | URL | Self-host overrides for the API endpoint and iframe origin |
customerName | string | Pre-fill customer name |
customerEmail | string | Pre-fill customer email |
customerId | string | Your internal customer ID |
position | bottom-right | bottom-left |
autoOpen | boolean | Open the chat on load |
buttonSize | number | Launcher button size in px |
panelWidth | number | Chat panel width in px |
panelHeight | number | Chat panel height in px |
zIndex | number | CSS z-index for the widget |
callbacks | object | onReady, onAuth, onOpen, onClose, onDestroy |
Defaults: buttonSize 60, panelWidth 400, panelHeight 620, zIndex 2147483647, autoOpen false, position bottom-right. Calls made before the auth handshake are queued and flushed after validation; every bridged call times out after 15 seconds. attachFile accepts a File, Blob, data URL or bare base64 plus an optional name; attachment snapshots carry id, name, type, size, status, progress and an error reason or URL. openComposer() also opens the panel locally, so isOpen() flips synchronously. updateConfig reloads the iframe and resets an in-progress conversation; only theme, customerName and customerEmail are re-applied.
Widget behaviour beyond these options (welcome and offline messages, input placeholder, file-upload, emoji and typing toggles, email-required, sound, online status, branding) is configured in the dashboard, not from the embed.
Conversation modellink
Flow states run idle → collecting_info → bot_conversation → handoff_pending → live_chat → ended | error; conversation statuses are BOT_ACTIVE, WAITING, ACTIVE, RESOLVED and CLOSED; channels are ai, live and ticket. The pre-chat info form is skipped only when a non-blank customerName was supplied. The transport heartbeats roughly every 10 seconds; a missed beat within about 16 seconds tears down, reconnects and replays missed messages from the server event log; connectivity is re-checked on online, visibilitychange and pageshow.
Widget lifecyclelink
- Auto-init runs on window load (immediately if the document is already complete) and only when
data-api-keyis present. - A second
init()returns null and warns that the widget is already initialized. - If the iframe never answers, a 10 second safety timeout removes the widget silently; on auth failure the root is removed,
onDestroyfires, queued calls reject, and the console explains that chat is unavailable, disabled or not configured. destroy()notifies the iframe, then rejects in-flight bridged calls with "widget destroyed".- The host page CSP must allow the widget origin in both
frame-srcandscript-src.
How the iframe bridge workslink
The widget loads in a sandboxed <iframe>. All communication between the host page and the widget uses postMessage with source-tag and origin validation:
- Host → widget messages are tagged with
ninstance-chat-host - Widget → host messages are tagged with
ninstance-chat
The widget fires onAuth after API key validation. The button stays hidden until onAuth confirms valid: true.
Permission scopes for Chat API keyslink
| Scope code | Description |
|---|---|
full-access | All chat permissions (recommended) |
ai-chatbot-access | Interact with AI chatbot |
live-chat-operations | Manage live chat sessions |
chat-configuration | Configure widget settings |