Chat Widget Integration
The Delivery Chat widget is a vanilla JavaScript embed that adds a chat launcher and chat window to any website. No framework required—works with React, Vue, plain HTML, or any stack.
Prerequisite: Application ID
You need an appId to use the widget. Create an application in your dashboard first.
AI Quickstart
Copy this prompt into your AI coding assistant (Cursor, Copilot, Claude, etc.) to get a working integration in one shot:
Quick Start
Add this snippet before </body> (or in <head>). The queue-stub pattern ensures calls are safe to make immediately — no race conditions:
<script>
(function(w,d,s,o){
w.DeliveryChat=w.DeliveryChat||function(){(w.DeliveryChat.queue=w.DeliveryChat.queue||[]).push(arguments)};
var js=d.createElement(s);js.async=1;js.src='https://api.deliverychat.online/widget.js';
d.head.appendChild(js);
})(window,document,'script');
DeliveryChat('init', { appId: 'YOUR_APP_ID' });
</script>Replace YOUR_APP_ID with your application UUID from the dashboard.
How the queue-stub works
The snippet creates a lightweight DeliveryChat function that queues all calls. When the real script loads, it replays the queue in order. This means:
- You can call
DeliveryChat('init', ...)immediately — no race condition. - Event listeners registered via
DeliveryChat('on', ...)before load are preserved. - The script loads asynchronously and never blocks page rendering.
Init Options
| Option | Type | Required | Description |
|---|---|---|---|
appId | string | Yes | Your application UUID from the dashboard |
apiBaseUrl | string | No | Override the API URL. Auto-detected from the script src by default |
position | "bottom-left" | "bottom-right" | No | Launcher position. Default: "bottom-right" |
autoOpen | boolean | No | Open chat automatically on load. Default: false |
autoOpenDelay | number | No | Delay in ms before auto-open. Default: 5000 |
colors | object | No | Override specific colors (e.g. { primary: "#6366f1" }) |
apiBaseUrl is optional for CDN
When using the CDN embed, apiBaseUrl is auto-detected from the script src attribute. Only pass it if you self-host the widget bundle on a different domain than the API. If provided, it must be origin-only — never append /api/v1.
Example with all options
DeliveryChat('init', {
appId: 'app_abc123',
position: 'bottom-left',
autoOpen: true,
autoOpenDelay: 3000,
colors: {
primary: '#6366f1',
background: '#ffffff',
text: '#0f172a',
},
});Controlling the Widget
After the script loads, DeliveryChat becomes an object with direct methods:
DeliveryChat.open(); // Open the chat window
DeliveryChat.close(); // Close it
DeliveryChat.toggle(); // Toggle open/close
DeliveryChat.hideWidget(); // Hide the launcher button
DeliveryChat.showWidget(); // Show it again
DeliveryChat.sendMessage('Hello!');
DeliveryChat.destroy(); // Remove widget and clean upQueue commands (before script loads)
Before the script finishes loading, use the function-call syntax:
DeliveryChat('init', { appId: 'YOUR_APP_ID' });
DeliveryChat('on', 'ready', function() { console.log('Widget ready'); });
DeliveryChat('sendMessage', 'Hello!');
DeliveryChat('identify', { name: 'Jane', email: 'jane@example.com' });Events
DeliveryChat.on('message:received', function(message) {
console.log('New message:', message.content);
});
DeliveryChat.on('unread:changed', function(data) {
document.title = data.count > 0 ? '(' + data.count + ') My App' : 'My App';
});Available events: ready, open, close, message:received, message:sent, conversation:started, conversation:resolved, unread:changed.
Destroying the Widget
To remove the widget (e.g. on SPA route change or logout):
DeliveryChat.destroy();This cleans up event listeners, removes the DOM, and resets state. You can call DeliveryChat.init() again afterward to re-initialize.
Settings from the API
The widget fetches configuration from the API on initialization:
GET {apiBaseUrl}/api/v1/widget/settings/:appIdThis endpoint is public (no auth). It returns JSON:
{
"settings": {
"colors": { "primary": "#0ea5e9", "background": "#ffffff" },
"font": { "family": "system-ui", "size": "14px" },
"position": { "corner": "bottom-right", "offset": "16px" },
"header": { "title": "Chat with us", "subtitle": "...", "showLogo": true, "logoUrl": "..." },
"launcher": { "icon": "chat", "label": "Open chat" },
"behavior": { "autoOpen": false, "autoOpenDelay": 5000 }
}
}Settings are stored in applications.settings (JSONB) and managed from your dashboard. Init options override API settings—e.g. position: "bottom-left" in init() overrides the API position.corner.
Customization
Dashboard settings
Configure colors, fonts, header, launcher, and behavior in your application settings. These are fetched automatically when the widget loads.
Init overrides
Override any setting at init time. Useful for A/B tests or per-page behavior:
DeliveryChat('init', {
appId: 'app_abc123',
position: 'bottom-left',
autoOpen: true,
colors: { primary: '#ff0000' },
});Launcher icons
The launcher supports three icon types: "chat", "question", and "message". Set via applications.settings.launcher.icon.
Security
The widget authenticates using domain-based origin validation. When you create an application, you register a domain (e.g. nike.com). The server validates that widget requests originate from that domain — no API key is exposed in client-side code.
- Requests from matching domains and subdomains are allowed (e.g.
shop.nike.commatchesnike.com) - Wildcard domains are supported (e.g.
*.nike.com) localhostorigins are allowed automatically during development
No API key needed
The widget only needs your appId. API keys are reserved for server-side SDK and REST API integrations where they can be kept secret.
How It Works
- Shadow DOM — Styles are isolated. Your site CSS does not affect the widget, and widget CSS does not leak out.
- Vanilla JS — No React, Vue, or other framework required. Works on any website.
- CDN-ready — The bundle is self-contained (~12KB gzipped) and can be served from any CDN.