Overview
The widget communicates with your application through six callback functions passed in the config. These callbacks let you synchronize your store’s cart, track analytics, and handle errors.
const widget = new VIZOCHOKWidget({
apiKey: 'pk_your_key',
storeId: 'your-store',
onCartChanged: (cart) => { /* ... */ },
onProductClick: (product) => { /* ... */ },
onSessionComplete: (summary) => { /* ... */ },
onError: (error) => { /* ... */ },
onConnect: () => { /* ... */ },
onDisconnect: () => { /* ... */ },
});
onCartChanged
Fired when the AI assistant adds, removes, updates, or clears items in the cart via webhooks. Use this callback to update your store’s cart UI in real time.
onCartChanged: (cart: CartChangedEvent) => void
CartChangedEvent
| Field | Type | Description |
|---|
action | string | The action that triggered the change: 'item_selected', 'item_removed', 'quantity_updated', or 'cart_cleared'. |
sku | string? | SKU of the affected product (absent for cart_cleared). |
name | string? | Name of the affected product. |
quantity | number? | New quantity of the affected product. |
price | number? | Price of the affected product. |
items | CartItem[] | Complete list of all items currently in the cart. |
total | number | Total cart value. |
CartItem
| Field | Type | Description |
|---|
sku | string | Product SKU. |
name | string | Product display name. |
price | number | Current price per unit. |
promo_price | number | null | Promotional price, if active. |
brand | string | null | Product brand name. |
quantity | number | Quantity in cart. |
Example: Sync with store cart
onCartChanged: (cart) => {
// Update your store's cart state
store.setCartItems(cart.items.map(item => ({
id: item.sku,
name: item.name,
price: item.promo_price ?? item.price,
qty: item.quantity,
})));
// Update cart total in your header
document.getElementById('cart-total').textContent = `${cart.total} $`;
// Update cart badge count
const itemCount = cart.items.reduce((sum, i) => sum + i.quantity, 0);
document.getElementById('cart-badge').textContent = String(itemCount);
},
The onCartChanged callback is a UI notification only. The actual cart change has already been confirmed via the server-to-server webhook to your backend. This callback is for updating the client-side UI.
onProductClick
Fired when a user clicks the “Add” button on a product card within the chat. This callback is informational — the cart update itself is handled by onCartChanged after the server confirms the webhook.
onProductClick: (product: ProductItem) => void
ProductItem
| Field | Type | Description |
|---|
sku | string | Product SKU. |
name | string | Product display name. |
price | number | Current price per unit. |
unit | string | Unit of measurement (e.g., 'pcs', 'kg'). |
quantity_step | number | Minimum quantity increment. |
quantity | number? | Selected quantity. |
brand | string | null | Product brand name. |
image_url | string | null | Product image URL. |
promo_price | number | null | Promotional price, if active. |
Example: Track product interactions
onProductClick: (product) => {
// Analytics tracking
analytics.track('product_selected_via_assistant', {
sku: product.sku,
name: product.name,
price: product.promo_price ?? product.price,
unit: product.unit,
});
// Open product detail page
window.open(`/products/${product.sku}`, '_blank');
},
onSessionComplete
Fired when the server sends a response with a session summary attached. This provides the current state of all items the user has selected during the conversation.
onSessionComplete: (summary: SessionSummary) => void
SessionSummary
| Field | Type | Description |
|---|
selected_items | CartItem[] | All items currently selected in the session. |
total | number | Total value of selected items. |
item_count | number | Number of distinct items selected. |
Example: Update checkout state
onSessionComplete: (summary) => {
console.log(`Session: ${summary.item_count} items, total ${summary.total}`);
// Sync with your checkout system
if (summary.item_count > 0) {
checkout.updateItems(summary.selected_items);
checkout.setTotal(summary.total);
}
},
onSessionComplete is also called when a session is restored on reconnect, providing the previously selected items.
onError
Fired on any error, whether from the server (rate limits, internal errors) or from the client (connection failures, message too large).
onError: (error: WidgetError) => void
| Field | Type | Description |
|---|
code | string | Machine-readable error code. See Error Codes for the full list. |
message | string | Localized human-readable error message in the widget’s configured language. |
Server Error Codes
rate_limit_exceeded, user_message_limit, user_conversation_limit, tenant_daily_token_limit, tenant_monthly_token_limit, agent_busy, message_too_large, invalid_json, internal_error, max_rounds_exceeded, session_token_limit, no_catalog_data
Client Error Codes
auth_error, auth_timeout, ws_error, message_too_large, queue_full, max_reconnect, connection_lost
Example: Error logging
onError: (error) => {
// Report to your error tracking service
errorTracker.captureError(new Error(error.message), {
tags: { source: 'vizochok', code: error.code },
});
// Show user-facing notification for critical errors
if (error.code === 'auth_error') {
showToast('Chat unavailable. Please refresh the page.');
}
},
onConnect
Fired when the WebSocket connection is authenticated and ready to send/receive messages. This is called after the auth_ok message is received from the server.
Example
onConnect: () => {
console.log('VIZOCHOK widget connected');
document.getElementById('ask-assistant-btn').disabled = false;
},
onDisconnect
Fired when the WebSocket connection is closed, whether intentionally (unmount/destroy) or due to a network issue. The widget automatically attempts reconnection for non-auth failures.
Example
onDisconnect: () => {
console.log('VIZOCHOK widget disconnected');
document.getElementById('ask-assistant-btn').disabled = true;
},
Common Patterns
Cart Synchronization
The most common integration pattern — keeping your store’s cart in sync with the AI assistant’s cart:
const widget = new VIZOCHOKWidget({
apiKey: 'pk_your_key',
storeId: 'your-store',
userId: currentUser.id,
onCartChanged: (cart) => {
// Replace your cart state entirely with the AI's cart
// The `items` array always contains the FULL cart, not just the delta
store.dispatch('cart/replaceAll', {
items: cart.items,
total: cart.total,
});
},
onSessionComplete: (summary) => {
// Also sync on session restore (page refresh / reconnect)
store.dispatch('cart/replaceAll', {
items: summary.selected_items,
total: summary.total,
});
},
});
The items field in onCartChanged contains the complete cart, not just the changed item. Always replace your entire cart state rather than trying to apply deltas.
Analytics Tracking
Track all widget interactions for analytics:
const widget = new VIZOCHOKWidget({
apiKey: 'pk_your_key',
storeId: 'your-store',
onConnect: () => {
analytics.track('assistant_connected');
},
onProductClick: (product) => {
analytics.track('assistant_product_click', {
sku: product.sku,
price: product.price,
});
},
onCartChanged: (cart) => {
analytics.track('assistant_cart_changed', {
action: cart.action,
item_count: cart.items.length,
total: cart.total,
});
},
onError: (error) => {
analytics.track('assistant_error', {
code: error.code,
});
},
});
Connection Status Indicator
Show connection state in your page:
const statusEl = document.getElementById('assistant-status');
const widget = new VIZOCHOKWidget({
apiKey: 'pk_your_key',
storeId: 'your-store',
onConnect: () => {
statusEl.className = 'status-online';
statusEl.textContent = 'Assistant online';
},
onDisconnect: () => {
statusEl.className = 'status-offline';
statusEl.textContent = 'Assistant offline';
},
});