navi-widget-sdk
v1.1.0
Published
Navi Chat Widget SDK - React, vanilla JS, headless client, and stream handler
Maintainers
Readme
Navi Widget SDK
A flexible chat widget SDK for integrating Navi AI into your applications. Supports both React components and vanilla JavaScript.
Installation
npm install navi-widget-sdkUsage
React Component
The SDK provides a NaviChat component with two display modes:
Floating Mode (Default)
A floating button that opens a chat window when clicked:
import { NaviChat } from 'navi-widget-sdk/react';
function App() {
return (
<NaviChat
widgetId="your-widget-id"
position="bottom-right" // or "bottom-left"
/>
);
}Embedded Mode
A static chat component that can be placed anywhere in your layout:
import { NaviChat } from 'navi-widget-sdk/react';
function App() {
return (
<div style={{ height: '600px', width: '400px' }}>
<NaviChat
widgetId="your-widget-id"
mode="embedded"
/>
</div>
);
}Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| widgetId | string | required | Widget ID from Navi dashboard |
| mode | 'floating' \| 'embedded' | 'floating' | Display mode |
| position | 'bottom-right' \| 'bottom-left' | 'bottom-right' | Position for floating mode |
| defaultOpen | boolean | false | Initial open state for floating mode |
| baseUrl | string | window.location.origin | Navi API base URL |
| sessionToken | string | - | Existing session token to resume a conversation |
| userToken | string | - | User identity token for verified users |
| runtimeParams | Record<string, unknown> | - | Runtime parameters for agent execution (see below) |
| theme | Partial<NaviWidgetTheme> | - | Custom theme overrides |
| greeting | string | 'Hello! How can I help you today?' | Initial greeting message |
| placeholder | string | 'Type your message...' | Input placeholder text |
| title | string | 'Chat with us' | Widget title |
| className | string | - | Additional CSS class name |
| style | React.CSSProperties | - | Inline styles |
| onOpen | () => void | - | Callback when widget opens |
| onClose | () => void | - | Callback when widget closes |
| onMessageSent | (message: string) => void | - | Callback when user sends a message |
| onMessageReceived | (message: NaviMessage) => void | - | Callback when response is received |
| onStatusUpdate | (status: string) => void | - | Callback when status updates (e.g., "Searching...") |
| onError | (error: Error) => void | - | Error callback |
Custom Theme
<NaviChat
widgetId="your-widget-id"
theme={{
primaryColor: '#10b981', // Button and user message color
backgroundColor: '#ffffff', // Chat window background
textColor: '#1f2937', // Text color
headerColor: '#10b981', // Header background
borderRadius: 16, // Border radius in pixels
}}
/>With Identity Verification
For verified users, pass the user token generated on your server:
<NaviChat
widgetId="your-widget-id"
userToken={generateUserToken(userId)} // From your backend
/>With Runtime Parameters
Runtime parameters are dynamic values that can be injected at execution time and referenced in agent configurations using ${params.key} syntax:
<NaviChat
widgetId="your-widget-id"
runtimeParams={{
user_token: 'jwt-abc123',
api_key: 'sk-secret-key',
user_id: 42,
organization_id: 'org-123'
}}
/>Where runtime parameters can be used in agent configuration:
- MCP server headers:
Authorization: Bearer ${params.user_token} - HTTP request headers:
X-API-Key: ${params.api_key} - Custom functions:
tools.getParam('user_id') - Agent instructions:
You are helping user ${params.user_id}
Built-in parameters (automatically available):
| Parameter | Description |
|-----------|-------------|
| params.current_date | Current date (YYYY-MM-DD) |
| params.current_datetime | Full ISO datetime |
| params.current_timestamp | Unix timestamp in ms |
| params.execution_id | Unique execution identifier |
Vanilla JavaScript (HTML Embed)
For non-React websites, use the vanilla JavaScript widget:
Basic Usage
Add this script tag to your HTML, just before the closing </body> tag:
<script
src="https://your-navi-url.com/widget.js"
data-widget-id="your-widget-id"
async
></script>Configuration Options
<script
src="https://your-navi-url.com/widget.js"
data-widget-id="your-widget-id"
data-position="bottom-left"
data-auto-open="true"
data-user-token="optional-user-token"
data-base-url="https://api.your-navi.com"
async
></script>| Attribute | Description |
|-----------|-------------|
| data-widget-id | Required. Widget ID from Navi dashboard |
| data-position | 'bottom-right' or 'bottom-left' (default: 'bottom-right') |
| data-auto-open | 'true' to auto-open widget on load |
| data-user-token | User identity token for verified users |
| data-base-url | Custom API base URL |
Programmatic Control
After the widget loads, you can control it programmatically:
// Open the widget
window.naviWidgetInstance.open();
// Close the widget
window.naviWidgetInstance.close();
// Toggle open/close
window.naviWidgetInstance.toggle();
// Set user token (for identity verification)
window.naviWidgetInstance.setUserToken('user-token-here');
// Set/Get session token (for session persistence)
window.naviWidgetInstance.setSession('session-token');
const token = window.naviWidgetInstance.getSession();
// Clear chat history
window.naviWidgetInstance.clearHistory();
// Destroy the widget
window.naviWidgetInstance.destroy();Manual Initialization
For more control, you can initialize the widget manually:
<script src="https://your-navi-url.com/widget.js"></script>
<script>
// Wait for the script to load
document.addEventListener('DOMContentLoaded', function() {
window.NaviWidget = new NaviWidget({
widgetId: 'your-widget-id',
position: 'bottom-right',
autoOpen: false,
userToken: 'optional-user-token',
baseUrl: 'https://api.your-navi.com',
sessionToken: 'optional-session-token',
greeting: 'Hello! How can I help?',
placeholder: 'Type your message...',
title: 'Chat with us',
theme: {
primaryColor: '#6366f1',
backgroundColor: '#ffffff',
textColor: '#1f2937',
headerColor: '#6366f1',
borderRadius: 12,
},
onOpen: function() {
console.log('Widget opened');
},
onClose: function() {
console.log('Widget closed');
},
onMessageSent: function(message) {
console.log('User sent:', message);
},
onMessageReceived: function(message) {
console.log('Bot replied:', message.content);
},
onStatusUpdate: function(status) {
console.log('Status:', status);
},
onError: function(error) {
console.error('Widget error:', error);
}
});
});
</script>Full Options Reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| widgetId | string | required | Widget ID from Navi dashboard |
| position | 'bottom-right' \| 'bottom-left' | 'bottom-right' | Widget position |
| autoOpen | boolean | false | Auto-open widget on load |
| baseUrl | string | window.location.origin | Navi API base URL |
| sessionToken | string | - | Existing session token to resume a conversation |
| userToken | string | - | User identity token for verified users |
| greeting | string | 'Hello! How can I help you today?' | Initial greeting message |
| placeholder | string | 'Type your message...' | Input placeholder text |
| title | string | 'Chat with us' | Widget title |
| theme | Partial<NaviWidgetTheme> | - | Custom theme overrides |
| onOpen | () => void | - | Callback when widget opens |
| onClose | () => void | - | Callback when widget closes |
| onMessageSent | (message: string) => void | - | Callback when user sends a message |
| onMessageReceived | (message: NaviMessage) => void | - | Callback when response is received |
| onStatusUpdate | (status: string) => void | - | Callback when status updates (e.g., "Searching...") |
| onError | (error: Error) => void | - | Error callback |
Headless Mode (API Client)
For custom integrations without any UI, such as middleware proxies, CLI applications, or server-side integrations, use the NaviHeadlessClient:
Installation & Import
import { NaviHeadlessClient } from 'navi-widget-sdk';
// or
import { NaviHeadlessClient } from 'navi-widget-sdk/headless';Basic Usage
const client = new NaviHeadlessClient({
widgetId: 'your-widget-id',
baseUrl: 'https://your-navi-instance.com',
});
// Create a session (required before sending messages)
const sessionToken = await client.createSession();
// Send a message with streaming callbacks
await client.sendMessage('Hello!', {
onDelta: (text) => process.stdout.write(text),
onStatus: (status) => console.log('Status:', status),
onComplete: (response) => console.log('\nDone:', response),
onError: (error) => console.error('Error:', error),
});Configuration Options
| Option | Type | Description |
|--------|------|-------------|
| widgetId | string | Required. Widget ID from Navi dashboard |
| baseUrl | string | Required. Navi API base URL |
| sessionToken | string | Optional. Existing session token to resume a conversation |
| userToken | string | Optional. User identity token for verified users |
| runtimeParams | Record<string, unknown> | Optional. Runtime parameters for agent execution |
Stream Callbacks
| Callback | Parameters | Description |
|----------|------------|-------------|
| onDelta | (text: string) | Called for each text chunk as it streams |
| onStatus | (status: string) | Called when status updates (e.g., "Searching...", "Processing...") |
| onComplete | (fullResponse: string) | Called when the response is complete |
| onError | (error: Error) | Called when an error occurs |
API Methods
// Session Management
await client.createSession(metadata?: Record<string, unknown>): Promise<string>
client.setSession(token: string): void
client.getSession(): string | null
client.hasSession(): boolean
// Messaging
await client.sendMessage(content: string, callbacks?: NaviStreamCallbacks, runtimeParams?: Record<string, unknown>): Promise<string>
await client.sendMessageSync(content: string): Promise<string> // Non-streaming
// History
client.getMessages(): NaviHeadlessMessage[]
client.clearMessages(): void
await client.fetchHistory(): Promise<NaviHeadlessMessage[]>
// User Identity
client.setUserToken(token: string | undefined): void
// Runtime Parameters
client.setRuntimeParams(params: Record<string, unknown> | undefined): void
client.getRuntimeParams(): Record<string, unknown> | undefinedRuntime Parameters
Runtime parameters can be set at construction, updated later, or passed per-message:
// Set at construction
const client = new NaviHeadlessClient({
widgetId: 'your-widget-id',
baseUrl: 'https://your-navi-instance.com',
runtimeParams: {
user_token: 'jwt-abc123',
api_key: 'sk-secret-key',
},
});
// Update later
client.setRuntimeParams({
user_token: 'new-token',
user_id: 42,
});
// Or pass per-message (overrides client-level params)
await client.sendMessage('Hello', {
onDelta: (text) => console.log(text),
}, {
user_token: 'message-specific-token',
});Middleware Proxy Example
For proxying Navi responses through your own middleware:
// middleware/navi-proxy.ts
import { NaviHeadlessClient } from 'navi-widget-sdk';
export async function handleChatRequest(req: Request): Promise<Response> {
const { message, sessionToken } = await req.json();
const client = new NaviHeadlessClient({
widgetId: process.env.NAVI_WIDGET_ID!,
baseUrl: process.env.NAVI_API_URL!,
sessionToken,
});
// Create session if not provided
let token = sessionToken;
if (!client.hasSession()) {
token = await client.createSession();
}
// Create a TransformStream for SSE
const { readable, writable } = new TransformStream();
const writer = writable.getWriter();
const encoder = new TextEncoder();
// Send message with streaming
client.sendMessage(message, {
onDelta: async (text) => {
await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'delta', text })}\n\n`));
},
onStatus: async (status) => {
await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'status', status })}\n\n`));
},
onComplete: async (response) => {
await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'complete', response, sessionToken: token })}\n\n`));
await writer.close();
},
onError: async (error) => {
await writer.write(encoder.encode(`data: ${JSON.stringify({ type: 'error', error: error.message })}\n\n`));
await writer.close();
},
});
return new Response(readable, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
});
}Session Persistence
To persist conversations across requests, store and reuse the session token:
// First request - create new session
const client = new NaviHeadlessClient({
widgetId: 'your-widget-id',
baseUrl: 'https://your-navi-instance.com',
});
const sessionToken = await client.createSession();
// Store sessionToken (e.g., in database, cookie, or cache)
// Subsequent requests - reuse session
const client2 = new NaviHeadlessClient({
widgetId: 'your-widget-id',
baseUrl: 'https://your-navi-instance.com',
sessionToken: storedSessionToken, // Pass the stored token
});
// Or set it after construction
client2.setSession(storedSessionToken);TypeScript Types
interface NaviHeadlessConfig {
widgetId: string;
baseUrl: string;
sessionToken?: string;
userToken?: string;
runtimeParams?: Record<string, unknown>;
}
interface NaviHeadlessMessage {
role: 'user' | 'assistant';
content: string;
timestamp: Date;
}
interface NaviStreamCallbacks {
onDelta?: (text: string) => void;
onStatus?: (status: string) => void;
onComplete?: (fullResponse: string) => void;
onError?: (error: Error) => void;
}Development
# Install dependencies
npm install
# Build the SDK
npm run build
# Watch mode
npm run dev
# Type checking
npm run typecheckBuild Output
After building, the following files are generated in dist/:
index.js/index.esm.js- Main library (CJS/ESM)react/index.js/react/index.esm.js- React componentsvanilla/navi-widget.js- Standalone vanilla JS widget (IIFE)*.d.ts- TypeScript declarations
License
MIT
