Custom Commands
Custom Commands extend Voice+ by allowing developers to define domain-specific, voice-driven commands that map directly to actions on the webpage or app. Instead of relying only on predefined Knowledge Base answers, Voice+ can listen for structured commands in real time and pass actionable payloads to the frontend SDK, where handlers carry out the requested behavior.
Overview
Custom Commands are powered by the Touchpoint SDK
Commands are defined using the
setCustomBidirectionalCommands
APIEach command has an action name, description, schema for validation, and handler function
Voice+ analyzes user utterances and matches them to registered commands
When a command matches, Voice+ returns a structured payload to the command handler
Quick Example
Here's a simple color selector command setup:
import { create } from '@nlxai/touchpoint-ui';
import * as z from 'zod/v4';
const COLOR_CHANGE_ACTION = 'changeColor';
const colorSchema = z.object({
color: z.string().describe('The color to change to'),
});
function handleColorChange(payload: any) {
document.body.style.backgroundColor = payload.color;
}
// Initialize touchpoint
const touchpoint = await create({
config: {
applicationUrl: 'YOUR_APPLICATION_URL',
headers: { 'nlx-api-key': 'YOUR_API_KEY' },
languageCode: 'en-US',
},
input: 'voiceMini',
bidirectional: {},
});
// Register commands
touchpoint.setCustomBidirectionalCommands([
{
action: COLOR_CHANGE_ACTION,
description: 'Change the background color',
schema: colorSchema,
handler: handleColorChange,
}
]);
User says: "Change color to blue" → Handler executes and changes the background color.
Command Properties
Each command object passed to setCustomBidirectionalCommands
supports these properties:
action
string
Yes
Unique identifier for the command
description
string
Yes
Human-readable description of what the command does
schema
ZodSchema
Yes
Zod schema for validating command payloads
handler
function
Yes
Function that executes when the command is triggered
Setup and Registration
Initialize Touchpoint and register custom commands:
import { create, TouchpointInstance } from '@nlxai/touchpoint-ui';
import * as z from 'zod/v4';
// Configuration constants
const NLX_APP_URL = 'https://bots.dev.studio.nlx.ai/c/YOUR_APPLICATION_URL';
const NLX_APP_API_KEY = 'your-api-key';
const DEFAULT_LANGUAGE = 'en-US';
let touchpointInstance: TouchpointInstance;
// Define schemas
const incrementSchema = z.object({
amount: z.number().optional().describe('Amount to increment by'),
});
const colorSchema = z.object({
color: z.string().describe('Color to change to'),
});
// Initialize Voice+
async function initializeTouchpoint() {
try {
const headers = { 'nlx-api-key': NLX_APP_API_KEY };
touchpointInstance = await create({
config: {
applicationUrl: NLX_APP_URL,
headers,
languageCode: DEFAULT_LANGUAGE,
},
input: 'voiceMini',
bidirectional: {},
});
// Register all commands after touchpoint is loaded
touchpointInstance.setCustomBidirectionalCommands([
{
action: 'increment',
description: 'Increment a counter by a specified amount',
schema: incrementSchema,
handler: (payload: any) => {
const amount = payload.amount || 1;
console.log(`Incrementing by ${amount}`);
}
},
{
action: 'changeColor',
description: 'Change the background color',
schema: colorSchema,
handler: (payload: any) => {
console.log(`Changing color to ${payload.color}`);
}
}
]);
console.log('Voice+ initialized successfully');
} catch (e) {
console.error('Failed to initialize Voice+:', e);
}
}
// Initialize on page load
initializeTouchpoint();
Schema Validation with Zod
Optionally, Use Zod schemas to define the expected structure of command payloads:
import * as z from 'zod/v4';
// Simple string parameter
const nameSchema = z.object({
name: z.string().describe('The name to use'),
});
// Optional number parameter
const incrementSchema = z.object({
amount: z.number().optional().describe('Amount to increment by'),
});
// Email validation
const emailSchema = z.object({
email: z.string().email().describe('Valid email address'),
});
// Enum values
const colorSchema = z.object({
color: z.enum(['red', 'blue', 'green']).describe('Color to apply'),
});
// Complex nested object
const filterSchema = z.object({
category: z.string().optional().describe('Category to filter by'),
price: z.object({
min: z.number().optional(),
max: z.number().optional(),
}).optional().describe('Price range filter'),
});
// Register commands using these schemas
touchpointInstance.setCustomBidirectionalCommands([
{
action: 'greet',
description: 'Greet a user by name',
schema: nameSchema,
handler: (payload: any) => {
console.log(`Hello, ${payload.name}!`);
}
},
{
action: 'increment',
description: 'Increment a counter',
schema: incrementSchema,
handler: (payload: any) => {
const amount = payload.amount || 1;
console.log(`Incrementing by ${amount}`);
}
},
{
action: 'sendEmail',
description: 'Send an email to a valid address',
schema: emailSchema,
handler: (payload: any) => {
console.log(`Sending email to ${payload.email}`);
}
},
{
action: 'changeTheme',
description: 'Change the theme color',
schema: colorSchema,
handler: (payload: any) => {
console.log(`Changing theme to ${payload.color}`);
}
},
{
action: 'filterProducts',
description: 'Filter products by category and price',
schema: filterSchema,
handler: (payload: any) => {
console.log('Filtering products:', payload);
}
}
]);
Common Use Cases
UI Interactions: Button clicks, form submissions, modal dialogs
Data Management: CRUD operations, filtering, sorting
Navigation: Page transitions, tab switching, section scrolling
Media Control: Play/pause, volume control, track selection
E-commerce: Add to cart, checkout, product filtering
Last updated