Skip to main content

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

FieldTypeDescription
actionstringThe action that triggered the change: 'item_selected', 'item_removed', 'quantity_updated', or 'cart_cleared'.
skustring?SKU of the affected product (absent for cart_cleared).
namestring?Name of the affected product.
quantitynumber?New quantity of the affected product.
pricenumber?Price of the affected product.
itemsCartItem[]Complete list of all items currently in the cart.
totalnumberTotal cart value.

CartItem

FieldTypeDescription
skustringProduct SKU.
namestringProduct display name.
pricenumberCurrent price per unit.
promo_pricenumber | nullPromotional price, if active.
brandstring | nullProduct brand name.
quantitynumberQuantity 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

FieldTypeDescription
skustringProduct SKU.
namestringProduct display name.
pricenumberCurrent price per unit.
unitstringUnit of measurement (e.g., 'pcs', 'kg').
quantity_stepnumberMinimum quantity increment.
quantitynumber?Selected quantity.
brandstring | nullProduct brand name.
image_urlstring | nullProduct image URL.
promo_pricenumber | nullPromotional 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

FieldTypeDescription
selected_itemsCartItem[]All items currently selected in the session.
totalnumberTotal value of selected items.
item_countnumberNumber 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

WidgetError

FieldTypeDescription
codestringMachine-readable error code. See Error Codes for the full list.
messagestringLocalized 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.
onConnect: () => void

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.
onDisconnect: () => void

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';
  },
});