E-commerce Integration Recipe
Complete patterns for building voice-powered e-commerce experiences.
Overview
This recipe provides a comprehensive guide for integrating Vowel into e-commerce applications, covering product browsing, cart management, checkout, and more.
Product Browsing
Search Products
typescript
vowel.registerAction('searchProducts', {
description: 'Search for products',
parameters: {
query: {
type: 'string',
description: 'Search query',
required: true
},
category: {
type: 'string',
description: 'Product category filter'
},
minPrice: {
type: 'number',
description: 'Minimum price'
},
maxPrice: {
type: 'number',
description: 'Maximum price'
}
}
}, async ({ query, category, minPrice, maxPrice }) => {
const results = await searchProducts({
query,
category,
priceRange: { min: minPrice, max: maxPrice }
});
// Navigate to results
const params = new URLSearchParams({ q: query });
if (category) params.set('category', category);
if (minPrice) params.set('min', minPrice.toString());
if (maxPrice) params.set('max', maxPrice.toString());
await router.push(`/search?${params.toString()}`);
await vowel.notifyEvent(
`Found ${results.length} products matching "${query}"`,
{ results: results.slice(0, 5) }
);
return { success: true, data: results };
});Browse by Category
typescript
vowel.registerAction('browseCategory', {
description: 'Browse products by category',
parameters: {
category: {
type: 'string',
description: 'Product category',
enum: ['electronics', 'clothing', 'home', 'books', 'sports'],
required: true
}
}
}, async ({ category }) => {
await router.push(`/category/${category}`);
const count = await getProductCount(category);
await vowel.notifyEvent(
`Showing ${count} products in ${category}`
);
return { success: true };
});View Product Details
typescript
vowel.registerAction('viewProduct', {
description: 'View product details',
parameters: {
productId: {
type: 'string',
description: 'Product ID',
required: true
}
}
}, async ({ productId }) => {
const product = await getProduct(productId);
if (!product) {
return {
success: false,
error: 'Product not found'
};
}
await router.push(`/product/${productId}`);
await vowel.notifyEvent(
`Viewing ${product.name}. Price: $${product.price}`,
{ product }
);
return { success: true, data: product };
});Get Product Information
typescript
vowel.registerAction('getProductInfo', {
description: 'Get information about current product',
parameters: {}
}, async () => {
const productId = getCurrentProductId();
if (!productId) {
return {
success: false,
error: 'Not viewing a product page'
};
}
const product = await getProduct(productId);
await vowel.notifyEvent(
`${product.name}. Price: $${product.price}. ${product.inStock ? 'In stock' : 'Out of stock'}`,
{ product }
);
return { success: true, data: product };
});Cart Management
Add to Cart
typescript
vowel.registerAction('addToCart', {
description: 'Add product to shopping cart',
parameters: {
productId: {
type: 'string',
description: 'Product ID',
required: true
},
quantity: {
type: 'number',
description: 'Quantity to add',
default: 1
},
size: {
type: 'string',
description: 'Product size (if applicable)'
},
color: {
type: 'string',
description: 'Product color (if applicable)'
}
}
}, async ({ productId, quantity, size, color }) => {
const product = await getProduct(productId);
if (!product) {
return { success: false, error: 'Product not found' };
}
if (!product.inStock) {
return { success: false, error: 'Product out of stock' };
}
// Add to cart
await cart.add({
productId,
quantity,
options: { size, color }
});
const cartTotal = await cart.getItemCount();
await vowel.notifyEvent(
`Added ${quantity} ${product.name} to cart. You now have ${cartTotal} items.`,
{ product, cartTotal }
);
return { success: true };
});View Cart
typescript
vowel.registerAction('viewCart', {
description: 'View shopping cart',
parameters: {}
}, async () => {
const items = await cart.getItems();
const total = await cart.getTotal();
await router.push('/cart');
if (items.length === 0) {
await vowel.notifyEvent('Your cart is empty');
} else {
await vowel.notifyEvent(
`You have ${items.length} items in your cart, totaling $${total.toFixed(2)}`,
{ items, total }
);
}
return { success: true, data: { items, total } };
});Update Cart Item
typescript
vowel.registerAction('updateCartQuantity', {
description: 'Update quantity of item in cart',
parameters: {
productId: {
type: 'string',
description: 'Product ID',
required: true
},
quantity: {
type: 'number',
description: 'New quantity',
required: true
}
}
}, async ({ productId, quantity }) => {
if (quantity <= 0) {
await cart.remove(productId);
await vowel.notifyEvent('Item removed from cart');
} else {
await cart.updateQuantity(productId, quantity);
await vowel.notifyEvent(`Quantity updated to ${quantity}`);
}
return { success: true };
});Remove from Cart
typescript
vowel.registerAction('removeFromCart', {
description: 'Remove item from cart',
parameters: {
productId: {
type: 'string',
description: 'Product ID',
required: true
}
}
}, async ({ productId }) => {
const product = await getProduct(productId);
await cart.remove(productId);
await vowel.notifyEvent(
`Removed ${product.name} from cart`
);
return { success: true };
});Clear Cart
typescript
vowel.registerAction('clearCart', {
description: 'Clear all items from cart',
parameters: {}
}, async () => {
await cart.clear();
await vowel.notifyEvent('Cart cleared');
return { success: true };
});Checkout Process
Start Checkout
typescript
vowel.registerAction('goToCheckout', {
description: 'Proceed to checkout',
parameters: {}
}, async () => {
const items = await cart.getItems();
if (items.length === 0) {
await vowel.notifyEvent('Your cart is empty. Add some items first.');
await router.push('/products');
return { success: false, error: 'Cart is empty' };
}
const user = getCurrentUser();
if (!user) {
await vowel.notifyEvent('Please sign in to checkout');
await router.push('/login?redirect=/checkout');
return { success: false, error: 'Authentication required' };
}
await router.push('/checkout');
await vowel.notifyEvent(
`Proceeding to checkout with ${items.length} items`
);
return { success: true };
});Apply Coupon
typescript
vowel.registerAction('applyCoupon', {
description: 'Apply discount coupon',
parameters: {
code: {
type: 'string',
description: 'Coupon code',
required: true
}
}
}, async ({ code }) => {
try {
const discount = await validateAndApplyCoupon(code);
await vowel.notifyEvent(
`Coupon applied! You saved $${discount.amount.toFixed(2)}`,
{ discount }
);
return { success: true, data: discount };
} catch (error) {
await vowel.notifyEvent('Invalid coupon code');
return {
success: false,
error: 'Invalid coupon code'
};
}
});Complete Order
typescript
vowel.registerAction('placeOrder', {
description: 'Place the order',
parameters: {
paymentMethod: {
type: 'string',
description: 'Payment method',
enum: ['credit_card', 'paypal', 'apple_pay'],
required: true
}
}
}, async ({ paymentMethod }) => {
try {
// Validate cart
const items = await cart.getItems();
if (items.length === 0) {
return { success: false, error: 'Cart is empty' };
}
// Validate shipping address
const shippingAddress = await getShippingAddress();
if (!shippingAddress) {
await vowel.notifyEvent('Please provide a shipping address');
return { success: false, error: 'Shipping address required' };
}
// Process order
await vowel.notifyEvent('Processing your order...');
const order = await createOrder({
items,
shippingAddress,
paymentMethod
});
// Clear cart
await cart.clear();
// Navigate to confirmation
await router.push(`/order/${order.id}`);
await vowel.notifyEvent(
`Order placed successfully! Your order number is ${order.id}. Total: $${order.total.toFixed(2)}`,
{ order }
);
return { success: true, data: order };
} catch (error) {
await vowel.notifyEvent('Failed to place order. Please try again.');
return {
success: false,
error: error.message
};
}
});Order Management
View Order History
typescript
vowel.registerAction('viewOrders', {
description: 'View order history',
parameters: {}
}, async () => {
const user = getCurrentUser();
if (!user) {
await vowel.notifyEvent('Please sign in to view orders');
await router.push('/login');
return { success: false, error: 'Authentication required' };
}
const orders = await getUserOrders(user.id);
await router.push('/account/orders');
await vowel.notifyEvent(
`You have ${orders.length} orders`,
{ orders }
);
return { success: true, data: orders };
});Track Order
typescript
vowel.registerAction('trackOrder', {
description: 'Track order status',
parameters: {
orderId: {
type: 'string',
description: 'Order ID',
required: true
}
}
}, async ({ orderId }) => {
const order = await getOrder(orderId);
if (!order) {
return { success: false, error: 'Order not found' };
}
await router.push(`/order/${orderId}`);
await vowel.notifyEvent(
`Order ${orderId} is ${order.status}. ${order.trackingInfo || ''}`,
{ order }
);
return { success: true, data: order };
});Wishlist
Add to Wishlist
typescript
vowel.registerAction('addToWishlist', {
description: 'Add product to wishlist',
parameters: {
productId: {
type: 'string',
description: 'Product ID',
required: true
}
}
}, async ({ productId }) => {
const user = getCurrentUser();
if (!user) {
await vowel.notifyEvent('Please sign in to use wishlist');
return { success: false, error: 'Authentication required' };
}
const product = await getProduct(productId);
await wishlist.add(user.id, productId);
await vowel.notifyEvent(
`Added ${product.name} to your wishlist`
);
return { success: true };
});View Wishlist
typescript
vowel.registerAction('viewWishlist', {
description: 'View wishlist',
parameters: {}
}, async () => {
const user = getCurrentUser();
if (!user) {
await vowel.notifyEvent('Please sign in to view wishlist');
return { success: false, error: 'Authentication required' };
}
const items = await wishlist.getItems(user.id);
await router.push('/wishlist');
await vowel.notifyEvent(
`You have ${items.length} items in your wishlist`,
{ items }
);
return { success: true, data: items };
});Product Recommendations
Get Recommendations
typescript
vowel.registerAction('showRecommendations', {
description: 'Show product recommendations',
parameters: {
based on: {
type: 'string',
description: 'Basis for recommendations',
enum: ['current_product', 'cart', 'history']
}
}
}, async ({ basedOn }) => {
let recommendations;
switch (basedOn) {
case 'current_product':
const productId = getCurrentProductId();
recommendations = await getRecommendations(productId);
break;
case 'cart':
const cartItems = await cart.getItems();
recommendations = await getCartRecommendations(cartItems);
break;
case 'history':
const user = getCurrentUser();
recommendations = await getPersonalizedRecommendations(user.id);
break;
}
await vowel.notifyEvent(
`Here are ${recommendations.length} recommended products`,
{ recommendations }
);
return { success: true, data: recommendations };
});Complete Example
typescript
// Setup Vowel for e-commerce
import { Vowel, createDirectAdapters } from '@vowel.to/client';
const { navigationAdapter, automationAdapter } = createDirectAdapters({
navigate: (path) => router.push(path),
routes: [
{ path: '/', description: 'Home page' },
{ path: '/products', description: 'All products' },
{ path: '/category/:category', description: 'Category page' },
{ path: '/product/:id', description: 'Product details' },
{ path: '/cart', description: 'Shopping cart' },
{ path: '/checkout', description: 'Checkout' },
{ path: '/account', description: 'Account' },
{ path: '/orders', description: 'Order history' }
],
enableAutomation: true
});
const vowel = new Vowel({
appId: 'your-app-id',
navigationAdapter,
automationAdapter
});
// Register all e-commerce actions
registerProductActions(vowel);
registerCartActions(vowel);
registerCheckoutActions(vowel);
registerOrderActions(vowel);
registerWishlistActions(vowel);Best Practices
- Authentication - Check user authentication for protected actions
- Validation - Validate cart and inventory before checkout
- Feedback - Provide clear voice feedback for all actions
- Error Handling - Handle out-of-stock, invalid coupons gracefully
- Progress Updates - Notify users during long operations
- Cart Persistence - Save cart state across sessions
- Security - Validate payment information server-side
- Accessibility - Ensure voice commands are discoverable
- Analytics - Track voice commerce conversions
- Testing - Test complete checkout flow with voice
Related
- Custom Actions - Advanced action patterns
- Navigation - Navigation patterns
- Event Notifications - Voice feedback
- API Reference - Complete API documentation