indigenius-ai-widget
v1.1.4
Published
TypeScript-compatible AI Widget SDK for Cdial with npm and CDN support
Downloads
43
Maintainers
Readme
Indigenius AI Widget
CdialWidget is a powerful SDK for integrating AI Agent call widget into your web application, offering functionalities to easily initiate and manage calls with your AI-powered customer service agents.
✨ Features
- 🎯 Full TypeScript Support - Complete type definitions included
- 📦 Multiple Installation Methods - npm, CDN, or direct URL
- ⚛️ Framework Agnostic - Works with React, Vue, Angular, Next.js, and more
- 🌐 Browser Compatible - Works in all modern browsers
- 🔧 Zero Configuration - Auto-detects TypeScript and provides IntelliSense
- 🎨 Customizable UI - Use built-in UI or build your own
Installation
To use the SDK in your project, you can either:
1. Install via npm (Recommended - Full TypeScript Support)
npm install indigenius-ai-widgetTypeScript types are automatically included! No need for @types/ packages or manual declarations.
2. Include the UMD build via CDN (For HTML/JavaScript projects)
<script src="https://cdn.jsdelivr.net/npm/indigenius-ai-widget@latest/dist/sdk.umd.js"></script>For TypeScript types with CDN usage, add this to your tsconfig.json:
{
"compilerOptions": {
"types": ["node_modules/indigenius-ai-widget/dist/index.d.ts"]
}
}Or install types separately:
npm install --save-dev indigenius-ai-widget3. Include the official URL (Direct integration)
<script type="module" src="https://widget.indigenius.ai/v1/index.js"></script>🚀 TypeScript Usage
The SDK is fully TypeScript compatible with complete type definitions included. No additional setup required!
Next.js Example (App Router)
// app/components/CdialWidget.tsx
'use client';
import { useEffect, useRef, useState } from 'react';
import { Cdial } from 'indigenius-ai-widget';
export default function CdialWidgetComponent() {
const widgetRef = useRef<Cdial.CdialWidget | null>(null);
const [callState, setCallState] = useState<'idle' | 'dialing' | 'connected' | 'ended'>('idle');
const [isReady, setIsReady] = useState(false);
useEffect(() => {
// Dynamic import to avoid SSR issues
import('indigenius-ai-widget').then(({ CdialWidget }) => {
const widget = new CdialWidget({
agentId: 'your-agent-id',
mountUI: false, // Control from your own UI
});
widgetRef.current = widget;
// Type-safe event listeners
widget.on('dialing', () => setCallState('dialing'));
widget.on('connected', () => setCallState('connected'));
widget.on('ended', () => setCallState('ended'));
widget.on('error', (error) => console.error('Widget error:', error));
widget.init();
setIsReady(true);
});
return () => widgetRef.current?.destroy();
}, []);
const toggleCall = () => {
widgetRef.current?.toggleCall();
};
return (
<div>
<h1>AI Agent Widget</h1>
<button
onClick={toggleCall}
disabled={!isReady}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
{callState === 'connected' ? '🔴 End Call' :
callState === 'dialing' ? '⏳ Dialing...' :
'📞 Start Call'}
</button>
{!isReady && <p>Loading widget...</p>}
</div>
);
}TypeScript with Vite/React
// src/components/Widget.tsx
import { useEffect, useRef, useState } from 'react';
import { Cdial, CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';
function Widget() {
const widgetRef = useRef<Cdial.CdialWidget | null>(null);
const [callState, setCallState] = useState<'idle' | 'dialing' | 'connected' | 'ended'>('idle');
useEffect(() => {
// Type-safe options
const options: CdialWidgetOptions = {
agentId: process.env.VITE_AGENT_ID || 'your-agent-id',
mountUI: true,
};
const widget = new CdialWidget(options);
widgetRef.current = widget;
// Fully typed event handlers
widget.on('dialing', () => setCallState('dialing'));
widget.on('connected', () => setCallState('connected'));
widget.on('ended', () => setCallState('ended'));
widget.on('error', (err) => {
console.error('Error:', err);
});
widget.init();
return () => widget.destroy();
}, []);
return (
<div>
<h1>Status: {callState}</h1>
</div>
);
}
export default Widget;Vue 3 + TypeScript
<!-- components/CdialWidget.vue -->
<template>
<div>
<h1>AI Agent Widget - {{ callState }}</h1>
<button @click="toggleCall" :disabled="!isReady">
{{ buttonLabel }}
</button>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
import { Cdial, CdialWidget } from 'indigenius-ai-widget';
type CallState = 'idle' | 'dialing' | 'connected' | 'ended';
const callState = ref<CallState>('idle');
const isReady = ref(false);
let widget: Cdial.CdialWidget | null = null;
onMounted(() => {
widget = new CdialWidget({
agentId: 'your-agent-id',
mountUI: false,
});
widget.on('dialing', () => (callState.value = 'dialing'));
widget.on('connected', () => (callState.value = 'connected'));
widget.on('ended', () => (callState.value = 'ended'));
widget.on('error', (err) => console.error(err));
widget.init();
isReady.value = true;
});
onBeforeUnmount(() => {
widget?.destroy();
});
const toggleCall = () => widget?.toggleCall();
const buttonLabel = computed(() =>
callState.value === 'connected' ? 'End Call' : 'Start Call'
);
</script>Angular with TypeScript
// app/components/widget/widget.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Cdial, CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';
@Component({
selector: 'app-cdial-widget',
template: `
<div>
<h1>AI Agent Widget - {{ callState }}</h1>
<button (click)="toggleCall()" [disabled]="!isReady">
{{ buttonLabel }}
</button>
</div>
`,
styles: [`
button {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`]
})
export class WidgetComponent implements OnInit, OnDestroy {
callState: 'idle' | 'dialing' | 'connected' | 'ended' = 'idle';
isReady = false;
private widget: Cdial.CdialWidget | null = null;
get buttonLabel(): string {
switch (this.callState) {
case 'connected': return '🔴 End Call';
case 'dialing': return '⏳ Dialing...';
default: return '📞 Start Call';
}
}
ngOnInit(): void {
const options: CdialWidgetOptions = {
agentId: 'your-agent-id',
mountUI: false,
};
this.widget = new CdialWidget(options);
this.widget.on('dialing', () => {
this.callState = 'dialing';
});
this.widget.on('connected', () => {
this.callState = 'connected';
});
this.widget.on('ended', () => {
this.callState = 'ended';
});
this.widget.on('error', (err) => {
console.error('Widget error:', err);
});
this.widget.init();
this.isReady = true;
}
ngOnDestroy(): void {
this.widget?.destroy();
}
toggleCall(): void {
this.widget?.toggleCall();
}
}Vanilla TypeScript
// src/app.ts
import { Cdial, CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';
class App {
private widget: Cdial.CdialWidget;
constructor() {
const options: CdialWidgetOptions = {
agentId: 'your-agent-id',
mountUI: true,
};
this.widget = new CdialWidget(options);
this.setupEventListeners();
this.widget.init();
}
private setupEventListeners(): void {
this.widget.on('dialing', () => {
console.log('Call is dialing...');
this.updateUI('dialing');
});
this.widget.on('connected', () => {
console.log('Call connected!');
this.updateUI('connected');
});
this.widget.on('ended', () => {
console.log('Call ended');
this.updateUI('ended');
});
this.widget.on('error', (error) => {
console.error('Call error:', error);
alert(`Error: ${error}`);
});
}
private updateUI(state: string): void {
const statusEl = document.getElementById('status');
if (statusEl) {
statusEl.textContent = `Status: ${state}`;
}
}
public cleanup(): void {
this.widget.destroy();
}
}
// Initialize the app
const app = new App();
// Cleanup on page unload
window.addEventListener('beforeunload', () => {
app.cleanup();
});TypeScript Type Definitions
The package exports the following types:
// Namespace export
import { Cdial } from 'indigenius-ai-widget';
// Named exports
import { CdialWidget, CdialWidgetOptions } from 'indigenius-ai-widget';
// Types
type CallState = 'idle' | 'dialing' | 'connected' | 'ended';
type EventType = 'dialing' | 'connected' | 'ended' | 'error';
type EventCallback = (data?: any) => void;
// Options interface
interface CdialWidgetOptions {
agentId: string;
mountUI?: boolean; // default: false
}
// Widget class methods
class CdialWidget {
constructor(options: CdialWidgetOptions);
init(): void;
startCall(theme?: any): Promise<void>;
endCall(): void;
toggleCall(): void;
isCalling(): boolean;
destroy(): void;
on(event: EventType, callback: EventCallback): void;
}🌐 CDN Usage with TypeScript
For projects using the CDN version but still want TypeScript support:
Option 1: Install Types Only
npm install --save-dev indigenius-ai-widgetThen in your HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Widget with CDN + TypeScript</title>
</head>
<body>
<indigenius-convai agent-id="your-agent-id"></indigenius-convai>
<!-- CDN Script -->
<script src="https://cdn.jsdelivr.net/npm/indigenius-ai-widget@latest/dist/sdk.umd.js"></script>
<script>
// TypeScript will recognize Cdial and CdialWidget types
window.addEventListener('load', () => {
const widget = window.widget; // Fully typed!
widget.on('connected', () => {
console.log('Connected');
});
});
</script>
</body>
</html>Option 2: Type Reference from CDN
Types are available at these URLs:
- jsDelivr:
https://cdn.jsdelivr.net/npm/indigenius-ai-widget@latest/dist/index.d.ts - unpkg:
https://unpkg.com/indigenius-ai-widget@latest/dist/index.d.ts
You can reference them in your TypeScript project or create a local type declaration.
Option 3: Manual Type Declaration
Create a indigenius-ai-widget.d.ts file in your project:
declare module 'indigenius-ai-widget' {
export namespace Cdial {
interface CdialWidgetOptions {
agentId: string;
mountUI?: boolean;
}
class CdialWidget {
constructor(options: CdialWidgetOptions);
init(): void;
toggleCall(): void;
startCall(theme?: any): Promise<void>;
endCall(): void;
isCalling(): boolean;
destroy(): void;
on(event: 'dialing' | 'connected' | 'ended' | 'error', callback: (data?: any) => void): void;
}
}
export const CdialWidget: typeof Cdial.CdialWidget;
export type CdialWidgetOptions = Cdial.CdialWidgetOptions;
}
declare global {
interface Window {
Cdial: typeof import('indigenius-ai-widget').Cdial;
CdialWidget: typeof import('indigenius-ai-widget').CdialWidget;
widget?: InstanceType<typeof import('indigenius-ai-widget').CdialWidget>;
}
}
export {};HTML Integration
You can integrate the widget into your HTML file with the following steps:
- Add the
<indigenius-convai>component to your HTML body to display the widget. - Include the SDK script (either from a CDN or local build).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Webapp</title>
</head>
<body>
<h1>Welcome to my random HTML site...</h1>
<!-- Add the widget component -->
<indigenius-convai agent-id="your-agent-id"></indigenius-convai>
<!-- Add the SDK script (local or CDN) -->
<script
type="module"
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/sdk.umd.js"
></script>
<script defer>
// Initialize event listeners
window.addEventListener("load", () => {
widget.on("dialing", () => {
console.log("Dialing detected");
});
widget.on("connected", () => {
console.log("Connected detected");
});
widget.on("ended", () => {
console.log("Ended detected");
});
widget.on("error", (err) => {
console.error("Error:", err);
});
});
</script>
</body>
</html>Framework Usage
Widget Options (CdialWidget Constructor Payload)
When creating a new CdialWidget instance, you pass an options object. Here are the available options:
| Option | Type | Required | Default | Description |
|------------|-----------|----------|---------|-----------------------------------------------------------------------------|
| agentId | string | Yes | — | The unique Agent ID for your AI agent. |
| mountUI | boolean | No | false | If true, the widget's floating UI is auto-mounted. If false, no UI is rendered and you control everything via the API. |
Example:
const widget = new CdialWidget({
agentId: 'your-agent-id',
mountUI: true, // Set to false to use your own UI
});Initialize the Widget
The init method is used to initialize the widget with your options. You must provide a valid agentId. If you set mountUI: true, the widget's floating UI will appear automatically. If mountUI: false, you can build your own UI and control the widget programmatically.
import { CdialWidget } from "indigenius-ai-widget";
const widget = new CdialWidget({
agentId: "your-agent-id",
mountUI: true, // or false for custom UI
});
widget.init().then(() => {
console.log("Widget initialized");
});Toggle Call
Use toggleCall to start or end a call. This method toggles the widget between the "call in progress" state and the "idle" state.
widget.toggleCall(); // Starts or ends the call based on the current stateYou can listen to events related to call state changes.
Event Listeners
The SDK supports various events that you can listen to for user interaction or state changes.
Example: Listening to Call Start and End Events
// Listen to call started
widget.on("callStarted", () => {
console.log("Call has started");
});
// Listen to call ended
widget.on("callEnded", () => {
console.log("Call has ended");
});Destroy the Widget
To clean up and remove the widget from the page, use the destroy method. This is useful if you need to remove the widget entirely after use.
widget.destroy();This method will remove all elements created by the widget and stop any ongoing call operations.
Full Example
Here’s a complete example of how to use the widget:
Modern Framework Integration
You can use the widget in React, Vue, or Angular. The mountUI option gives you full control over whether the floating widget UI appears, or if you want to build your own UI and use the widget's API.
React Example (Live Demo)
import './App.css';
import { useEffect, useRef, useState } from 'react';
import { CdialWidget } from 'indigenius-ai-widget';
function App() {
const widgetRef = useRef(null);
const [callState, setCallState] = useState('idle');
const [widgetReady, setWidgetReady] = useState(false);
useEffect(() => {
// Use mountUI: false to control the call from your React button only
const widget = new CdialWidget({
agentId: 'your-agent-id',
mountUI: false, // Only your React button will control the call
});
widgetRef.current = widget;
widget.on('dialing', () => setCallState('dialing'));
widget.on('connected', () => setCallState('connected'));
widget.on('ended', () => setCallState('ended'));
widget.on('error', console.error);
widget.init().then(() => setWidgetReady(true));
return () => widget.destroy();
}, []);
const toggleCall = () => widgetRef.current?.toggleCall();
return (
<div>
<h1>Cdial Widget Demo</h1>
<button onClick={toggleCall} disabled={!widgetReady}>
{callState === 'connected'
? 'End Call'
: callState === 'dialing'
? 'Dialing...'
: 'Start Call'}
</button>
{!widgetReady && <p>Loading widget...</p>}
</div>
);
}
export default App;Vue Example (Live Demo: N/A)
<template>
<div>
<h1>Cdial Widget Demo (Vue)</h1>
<button @click="toggleCall">{{ buttonLabel }}</button>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
import { CdialWidget } from 'indigenius-ai-widget';
const callState = ref('idle');
let widget = null;
onMounted(() => {
widget = new CdialWidget({
agentId: 'your-agent-id',
mountUI: true, // Set to false to use your own UI
});
widget.on('dialing', () => callState.value = 'dialing');
widget.on('connected', () => callState.value = 'connected');
widget.on('ended', () => callState.value = 'ended');
widget.on('error', console.error);
widget.init();
});
onBeforeUnmount(() => {
widget?.destroy();
});
const toggleCall = () => widget?.toggleCall();
const buttonLabel = computed(() =>
callState.value === 'connected' ? 'End Call' : 'Start Call'
);
</script>Angular Example (Live Demo: N/A)
// app.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CdialWidget } from 'indigenius-ai-widget';
@Component({
selector: 'app-root',
template: `
<h1>Cdial Widget Demo (Angular)</h1>
<button (click)="toggleCall()">{{ buttonLabel }}</button>
`
})
export class AppComponent implements OnInit, OnDestroy {
callState = 'idle';
widget: any;
get buttonLabel() {
return this.callState === 'connected' ? 'End Call' : 'Start Call';
}
ngOnInit() {
this.widget = new CdialWidget({
agentId: 'your-agent-id',
mountUI: true, // Set to false to use your own UI
});
this.widget.on('dialing', () => this.callState = 'dialing');
this.widget.on('connected', () => this.callState = 'connected');
this.widget.on('ended', () => this.callState = 'ended');
this.widget.on('error', console.error);
this.widget.init();
}
ngOnDestroy() {
this.widget?.destroy();
}
toggleCall() {
this.widget?.toggleCall();
}
}Summary
- mountUI: true — Widget’s floating UI is auto-mounted (recommended for most use cases).
- mountUI: false — No UI is rendered; you control everything via the widget API (advanced/custom UI).
- The widget is fully self-contained and will not create duplicate UIs, even if instantiated multiple times in a framework.
- All public methods (
init,destroy,toggleCall,on, etc.) are available on the widget instance.
Methods
init()
Initializes the widget with the given agentId and sets up the UI.
Returns: Promise<void>
toggleCall()
Starts or ends a call based on the current widget state.
Returns: void
destroy()
Destroys the widget, removing all associated elements and cleaning up resources.
Returns: void
Events
The widget emits several events that you can listen to for customizing your application's behavior. Below is a list of available events, their descriptions, and usage examples.
📡 dialing
Emitted when the widget starts attempting to connect to the AI agent.
Example:
myCdialWidget.on("dialing", () => {
console.log("Dialing detected");
});🔗 connected
Emitted when the connection to the AI agent is successfully established.
Example:
myCdialWidget.on("connected", () => {
console.log("Connected detected");
});❌ ended
Emitted when the call has ended or was terminated.
Example:
myCdialWidget.on("ended", () => {
console.log("Ended detected");
});⚠️ error
Emitted if there is an internal error during the operation of the widget.
Payload: err (Error or string) – details about the error that occurred.
Example:
myCdialWidget.on("error", (err) => {
console.error("Error:", err);
});You can register these event listeners after the widget has loaded:
<script defer>
window.addEventListener("load", () => {
myCdialWidget.on("dialing", () => {
console.log("Dialing detected");
});
myCdialWidget.on("connected", () => {
console.log("Connected detected");
});
myCdialWidget.on("ended", () => {
console.log("Ended detected");
});
myCdialWidget.on("error", (err) => {
console.error("Error:", err);
});
});
</script>🔧 TypeScript Verification
Verify Types are Working
After installing the package, verify TypeScript support:
// test.ts
import { Cdial, CdialWidget } from 'indigenius-ai-widget';
// Should show IntelliSense for options
const widget = new CdialWidget({
agentId: 'test', // ✅ Required
mountUI: true, // ✅ Optional with autocomplete
});
// Should show method autocomplete
widget.init();
widget.toggleCall();
widget.on('connected', () => {}); // ✅ Event names autocompleted
widget.destroy();Run TypeScript compiler:
npx tsc test.ts --noEmitIf no errors appear, TypeScript is configured correctly! ✅
Troubleshooting TypeScript
Problem: Types not detected
Solutions:
- Ensure package is installed:
npm install indigenius-ai-widget - Restart your IDE/TypeScript server
- Check
tsconfig.jsonhasmoduleResolution: "node" - Run
npm installagain to refresh types
Problem: CDN usage without types
Solution:
# Install types as dev dependency
npm install --save-dev indigenius-ai-widgetIDE Support
The package works with:
- ✅ VS Code (IntelliSense + autocomplete)
- ✅ WebStorm/IntelliJ IDEA
- ✅ Sublime Text (with LSP)
- ✅ Vim/Neovim (with CoC or LSP)
📚 Additional Resources
- 📘 Complete TypeScript Guide
- 💡 TypeScript Usage Examples
- ⚛️ Next.js Example
- 🌐 HTML Integration Example
- 📦 npm Package
- 🐙 GitHub Repository
This SDK is released under the MIT License. See LICENSE for more details.
