Behavioral customization APIs
The Zendesk Messaging Web Widget provides behavioral customization APIs that give you programmatic control over conversations and messages. These APIs enable advanced integration scenarios including contextual conversation creation, message interception, and navigation control in multi-conversation mode.
Prerequisites:
- Zendesk Messaging Web Widget installed
- For navigation and conversation management APIs, multi-conversation mode is enabled
- Basic familiarity with JavaScript and the Zendesk Web Widget
Use cases
1. Hide business messages from users
Scenario: Your AI Agent sends internal system messages (for example, workflow_triggered or context_received) that trigger a specific flow, but users shouldn't see them in the widget UI.
APIs used: beforeMessageDisplay delegate, sendMessage
zE("messenger:set", "beforeMessageDisplay", function (message, data) {// Hide messages with metadata flag 'internal_only'if (message.metadata && message.metadata.internal_only === true) {return null // Message won't be displayed to user}return message // Display normally})
const conversationId = getStoredConversationId() // Your storage logiczE("messenger","sendMessage",{content: {type: "text",text: "Hidden message triggering specific workflow"},metadata: {internal_only: true}},conversationId,function (error, messageResult) {if (error) {console.error("Failed to send message:", error)} else {console.log("Message sent:", messageResult.id)}})
2. Send programmatic messages (for example, order updates)
Scenario: A user completes a checkout on your site, and you want to send an order confirmation message into their existing support conversation.
APIs used: sendMessage
// After checkout completesconst conversationId = getStoredConversationId() // Your storage logiczE("messenger","sendMessage",{content: {type: "text",text: "Your order #12345 has been confirmed!"},metadata: {order_id: "12345",order_total: "99.99",event_type: "order_confirmation"}},conversationId,function (error, messageResult) {if (error) {console.error("Failed to send message:", error)} else {console.log("Message sent:", messageResult.id)}})
3. Multi-conversation navigation
Scenario: You want users to have separate conversations for Sales, Support, and Billing. When they click "Contact Sales," load the existing Sales conversation or create one if it doesn't exist.
APIs used: fetchConversations, newConversation, navigation
function openDepartmentChat(department) {zE("messenger", "fetchConversations", 0, function (error, result) {const existingConv = result.data.find(conv => conv.displayName === `${department} Support`)if (existingConv) {zE("messenger:ui", "navigation", {screen: "Conversation",options: { conversationId: existingConv.id }})} else {zE("messenger","newConversation",{displayName: `${department} Support`,metadata: { department }},function (error, conversationResult) {zE("messenger:ui", "navigation", {screen: "Conversation",options: { conversationId: conversationResult.id }})})}})}// Usagedocument.getElementById("sales-button").onclick = () => {openDepartmentChat("Sales")}
4. React to incoming messages
Scenario: You want to trigger custom UI updates, analytics events, or browser notifications when a message is received.
APIs used: messageReceived event
zE("messenger:on", "messageReceived", function (event) {console.log("Message received:", event.payload.message.id)// Track analyticsif (typeof analytics !== "undefined") {analytics.track("message_received", {conversation_id: event.payload.conversation.id,message_role: event.payload.message.role,source_type: event.payload.message.source.type})}// Show browser notification if window is not focusedif (document.hidden && Notification.permission === "granted") {new Notification("New message from support")}})
Available APIs
For a complete parameter reference and more examples, see the Core messaging Web Widget API.
- Create New Conversation (Programmatic): Creates a new conversation with callback support for handling success and error cases. Use when you need programmatic access to conversation details or want to attach metadata to the initial message.
- Send Message: Sends a message on behalf of the end user to an existing conversation.
- Fetch Conversations: Retrieves a paginated list of conversations for the current user.
- Navigation: Navigates to a specific screen within the widget. Available in multi-conversation mode only.
- Set Delegate - Before Message Sent: Registers a callback to intercept and modify message metadata before a message is sent.
- Set Delegate - Before Message Display: Registers a callback to intercept and modify incoming messages before they are displayed, or hide them entirely.
- On Message Received: Fires when a new message is received in any conversation.
Best practices
Metadata size limits
- Conversation metadata: 4KB max
- Message metadata: 4KB max
- Use metadata for identifiers and context, not large payloads
Rate limiting
APIs that make backend calls (newConversation, sendMessage, fetchConversations) are rate-limited on the server side. Avoid calling them in tight loops.
Security
- Never expose sensitive data in metadata that will be passed to client-side delegates
- Sanitize user input before passing it to
sendMessage - Be cautious with
beforeMessageDisplaymodifications—they are visual only and won't affect transcripts
Delegate performance
Keep delegate functions (beforeMessageSent, beforeMessageDisplay) fast and synchronous. Heavy processing will block widget operations.
Error handling
APIs that accept a callback use an error-first pattern - the callback receives error as the first argument and the result as the second. Always check whether error is non-null before using the result, and log errors for debugging.
Storage of conversation IDs
If your use case requires mapping conversations to orders, user sessions, or departments, store conversation ids on your backend or in browser storage (localStorage, sessionStorage) for retrieval.
Migration from Sunshine Conversations Web Messenger
If you're migrating from the Sunshine Conversations SDK, here are the equivalent APIs:
| Sunshine Conversations Web Messenger | Zendesk Messaging Web Widget |
|---|---|
Smooch.createConversation(options) | zE('messenger', 'newConversation', options, callback, errorCallback) |
Smooch.loadConversation(conversationId) | zE('messenger:ui', 'navigation', { screen: 'Conversation', options: { conversationId } }) |
Smooch.getConversations() | zE('messenger', 'fetchConversations', offset, callback, errorCallback) |
Smooch.sendMessage(message, conversationId) | zE('messenger', 'sendMessage', message, conversationId, callback, errorCallback) |
delegate: { beforeSend } | zE('messenger:set', 'beforeMessageSent', callback) |
delegate: { beforeDisplay } | zE('messenger:set', 'beforeMessageDisplay', callback) |
Smooch.on('message:received') | zE('messenger:on', 'messageReceived', callback) |
Key differences:
- Zendesk APIs use callback-based patterns instead of Promises
- Response objects are trimmed to exclude sensitive information
- Navigation is handled via a unified
navigationAPI rather than a separateloadConversation
FAQ
Q: Can I send messages on behalf of bots or agents?
A: No. The sendMessage API only sends messages on behalf of the current end user.
Q: Will messages hidden by beforeMessageDisplay appear in downloaded transcripts?
A: Yes. The delegate only affects visual display in the widget UI, not the server-side transcript.
Q: Can I use these APIs in single-conversation mode?
A: Most APIs work in single-conversation mode, except navigation and fetchConversations, which require multi-conversation mode. createConversation API in single-conversation mode will allow to create the initial conversation only.
Q: What happens if I call newConversation but the user has reached their conversation limit?
A: The callback will receive a ConversationCreationError as its first argument.
Q: Can I modify message content in beforeMessageSent?
A: Currently, only metadata can be modified. Support for modifying other fields may be added based on customer feedback.