Developers
Public REST API (/v1/public/*) + outbound webhooks. Lihat docs di /api-docs.
Live Chat Widget
Add a floating chat button to any website in under a minute. Bundle size is under 30KB gzipped, loads asynchronously, and never blocks your page render.
- Create a Live Chat channel at Channels → New → Live Chat Widget. Copy the channel ID from the resulting card.
- Paste the embed snippet below into the <head> or before </body>.
- Publish. The widget picks up your agent config, brand color, and locale.
Standard embed (any site)
Vanilla HTML tag. Works with WordPress, Shopify, Webflow.
<!-- Danum AI Live Chat Widget --> <script async src="https://ai.numintek.com/widget/widget.js" data-channel-id="YOUR_CHANNEL_ID" data-primary-color="#6366F1" data-position="bottom-right" data-locale="en" ></script>
Available data-* attributes
data-channel-id- required. From your Live Chat channel.data-primary-color- hex or rgb. Overrides channel default.data-position- bottom-right | bottom-left | top-right | top-left.data-locale- en | id. Defaults to browser lang, then en.data-open- auto | closed. Default closed.data-hide-launcher- true to hide floating button (control via JS API).
React / Next.js
Client-only mount to skip SSR flash.
import { useEffect } from 'react';
export function DanumWidget({ channelId }: { channelId: string }) {
useEffect(() => {
const s = document.createElement('script');
s.async = true;
s.src = 'https://ai.numintek.com/widget/widget.js';
s.dataset.channelId = channelId;
s.dataset.primaryColor = '#6366F1';
s.dataset.position = 'bottom-right';
document.body.appendChild(s);
return () => { s.remove(); };
}, [channelId]);
return null;
}Identify known users
Skip the anonymous handshake. Passing identify auto-links the conversation to a customer record.
// Programmatic identify - pass known-user context before the widget loads a session.
window.DanumWidget = window.DanumWidget || {};
window.DanumWidget.identify = {
externalId: 'user_123',
name: 'Budi Santoso',
email: '[email protected]',
phone: '+628123456789',
metadata: { plan: 'PROFESSIONAL' },
};Call this before the widget script loads, or after with window.DanumWidget.identify(...) . externalId must be your internal user ID; it is never displayed to agents.
JS API
Programmatic control after the widget loads.
window.DanumWidget.open();
window.DanumWidget.close();
window.DanumWidget.toggle();
window.DanumWidget.setLocale('id');
window.DanumWidget.on('conversation.started', (id) => { /* analytics */ });
window.DanumWidget.on('message.sent', (msg) => { /* track */ });
window.DanumWidget.reset(); // clears local sessionContent Security Policy
If your site sends a CSP header, allow these origins.
Content-Security-Policy: script-src 'self' https://ai.numintek.com; connect-src 'self' https://ai.numintek.com wss://ai.numintek.com; frame-src https://ai.numintek.com; img-src 'self' data: https://ai.numintek.com;
Troubleshooting
Common gotchas and how to solve them.
Widget doesn't appear
- Open DevTools → Network → look for danum-widget.js. Should be 200.
- Check data-channel-id matches your channel exactly.
- Confirm the channel is Active on the Channels page.
Widget loads but chat fails
- WebSocket blocked - check CSP and any proxy rewriting Upgrade headers.
- Tenant quota exhausted - see Usage page.
- Agent published? Draft-only agents don't serve production traffic.
Styling clashes
- Widget runs inside a Shadow DOM - your CSS won't leak in or out.
- Custom fonts → contact support to whitelist your font URL.
Privacy & PDP compliance
- Widget stores only a session ID in localStorage.
- Full transcript lives in your tenant DB, encrypted at rest.
- Use widget.reset() when a user signs out to clear the session.