Event Notifications
Learn how to programmatically trigger AI voice responses for application events.
Overview
Event notifications allow you to make the AI speak about things happening in your app without requiring user voice input. This is perfect for:
- Order confirmations
- Timer expiry
- New messages
- System alerts
- Status updates
Basic Usage
typescript
import { vowel } from './vowel.client';
// Simple notification
await vowel.notifyEvent('Order placed successfully!');
// Notification with context
await vowel.notifyEvent('New message received', {
from: 'John Doe',
preview: 'Hey, are you available?',
timestamp: new Date().toISOString()
});Common Patterns
Order Confirmation
typescript
async function handleOrderPlaced(order: Order) {
// Process the order
const result = await processOrder(order);
// Notify user via voice
await vowel.notifyEvent('Your order has been placed successfully!', {
orderId: result.id,
total: result.total,
estimatedDelivery: result.estimatedDelivery
});
}Timer Expiry
typescript
class VoiceTimer {
private timerId: number | null = null;
start(minutes: number) {
this.timerId = setTimeout(async () => {
await vowel.notifyEvent(`Your ${minutes}-minute timer has expired`);
}, minutes * 60 * 1000);
}
cancel() {
if (this.timerId) {
clearTimeout(this.timerId);
this.timerId = null;
}
}
}
// Usage
const timer = new VoiceTimer();
timer.start(5); // 5-minute timerNew Message Notification
typescript
// Listen for new messages
socket.on('new-message', async (message) => {
await vowel.notifyEvent('You have a new message', {
from: message.sender.name,
preview: message.text.substring(0, 50),
timestamp: message.timestamp
});
});Shopping Cart Updates
typescript
async function addToCart(product: Product, quantity: number) {
// Add to cart
cart.add(product, quantity);
// Notify user
await vowel.notifyEvent('Item added to cart', {
productName: product.name,
quantity,
cartTotal: cart.items.length,
subtotal: cart.getSubtotal()
});
}Form Submission
typescript
async function handleFormSubmit(formData: FormData) {
try {
await submitForm(formData);
await vowel.notifyEvent('Form submitted successfully!', {
formType: 'contact',
timestamp: new Date().toISOString()
});
} catch (error) {
await vowel.notifyEvent('Form submission failed', {
error: error.message
});
}
}Advanced Patterns
Debounced Notifications
Prevent notification spam by debouncing:
typescript
import { debounce } from 'lodash';
const notifyCartUpdate = debounce(async (cart: Cart) => {
await vowel.notifyEvent('Cart updated', {
itemCount: cart.items.length,
total: cart.getTotal()
});
}, 1000);
// Usage
function updateCart(product: Product) {
cart.add(product);
notifyCartUpdate(cart); // Will only notify after 1 second of inactivity
}Conditional Notifications
Only notify based on user preferences:
typescript
async function notifyIfEnabled(event: string, context?: any) {
const preferences = await getUserPreferences();
if (preferences.voiceNotifications) {
await vowel.notifyEvent(event, context);
}
}
// Usage
await notifyIfEnabled('Order placed', { orderId: '12345' });Priority Notifications
Handle urgent vs. non-urgent notifications:
typescript
enum NotificationPriority {
LOW = 'low',
NORMAL = 'normal',
HIGH = 'high',
URGENT = 'urgent'
}
async function notify(
message: string,
priority: NotificationPriority,
context?: any
) {
const prefixes = {
[NotificationPriority.LOW]: '',
[NotificationPriority.NORMAL]: '',
[NotificationPriority.HIGH]: 'Important: ',
[NotificationPriority.URGENT]: 'Urgent: '
};
await vowel.notifyEvent(prefixes[priority] + message, {
...context,
priority
});
}
// Usage
await notify('System maintenance in 5 minutes', NotificationPriority.HIGH);
await notify('Critical error occurred', NotificationPriority.URGENT);Queued Notifications
Queue notifications to prevent overlapping speech:
typescript
class NotificationQueue {
private queue: Array<{ message: string; context?: any }> = [];
private processing = false;
async add(message: string, context?: any) {
this.queue.push({ message, context });
if (!this.processing) {
await this.process();
}
}
private async process() {
this.processing = true;
while (this.queue.length > 0) {
const notification = this.queue.shift()!;
await vowel.notifyEvent(notification.message, notification.context);
// Wait for AI to finish speaking
await this.waitForSpeechEnd();
}
this.processing = false;
}
private async waitForSpeechEnd(): Promise<void> {
return new Promise((resolve) => {
const checkSpeaking = () => {
if (!vowel.isAISpeaking()) {
resolve();
} else {
setTimeout(checkSpeaking, 100);
}
};
checkSpeaking();
});
}
}
// Usage
const notificationQueue = new NotificationQueue();
await notificationQueue.add('First notification');
await notificationQueue.add('Second notification');
await notificationQueue.add('Third notification');React Integration
Hook for Event Notifications
tsx
import { useVowel } from '@vowel.to/client/react';
export function useVoiceNotification() {
const { client } = useVowel();
const notify = useCallback(async (message: string, context?: any) => {
if (client.state.isConnected) {
await client.notifyEvent(message, context);
}
}, [client]);
return { notify };
}
// Usage in component
function OrderConfirmation({ order }: { order: Order }) {
const { notify } = useVoiceNotification();
useEffect(() => {
notify('Order confirmed!', {
orderId: order.id,
total: order.total
});
}, [order, notify]);
return <div>Order #{order.id} confirmed!</div>;
}Error Handling
Always handle errors when sending notifications:
typescript
async function safeNotify(message: string, context?: any) {
try {
await vowel.notifyEvent(message, context);
} catch (error) {
console.error('Failed to send voice notification:', error);
// Fallback to visual notification
showToast(message);
}
}Best Practices
- Keep messages concise - Voice notifications should be brief and clear
- Provide context - Include relevant data in the context object
- Don't spam - Use debouncing for frequent events
- Check connection - Verify session is active before notifying
- Handle errors - Always have a fallback for failed notifications
- Respect preferences - Allow users to disable voice notifications
Related
- Speaking State Tracking - Track when AI is speaking
- Custom Actions - Define voice commands
- API Reference - Complete API documentation