Web Core API

Build a custom chat UI on KustomerCore, the headless web chat SDK. Loading core.js, init, conversations, messages, typing, read state, knowledge base, CSAT, identity, and every event.

core.js is the chat SDK without a UI. It handles identity, conversations, messages, realtime delivery and the knowledge base, and you render everything yourself. The widget is built on the same Core, so anything the widget does, your UI can do too.

Load Core

index.html
<script
  src="https://cdn.kustomerapp.com/chat-web/core.js"
  data-kustomer-api-key="YOUR_CHAT_KEY"
></script>
<script>
  window.addEventListener('kustomerCoreLoaded', function () {
    KustomerCore.init({ brandId: 'YOUR_BRAND_ID' }, function (res, error) {
      if (error) return console.error(error)
      console.log('Chat settings', res.settings)
    })
  })
</script>

Use a chat key with only the org.tracking role, as for the widget. Core runs in a hidden iframe, defines window.KustomerCore, and fires kustomerCoreLoaded when it's ready. init calls made before that are queued.

Every method takes an optional callback, called as callback(response, error). Check error first: it's an Error with optional status, code, title and source from the API.

init

KustomerCore.init(options, callback)
brandIdstring
assistantIdstring
scheduleIdstring
langstring
enableUrlUnfurlingboolean

The response's settings is what admins configured for the brand in Kustomer. Use it to render your UI:

SettingMeaning
teamName, teamIconUrlWho the customer is talking to
greeting, waitMessageText for the empty state and while waiting for an agent
colorsThe brand's chat colors
widgetTypeWhether the brand uses chat, the knowledge base, or both
noHistory, singleSessionChatHide past conversations, or allow only one open conversation
disableAttachments, closableChatWhether customers can attach files or end conversations
offhoursDisplay, offhoursMessage, offhoursImageUrlWhat to show outside business hours
activeAssistant, knowledgeBaseIdThe brand's assistant and knowledge base
domainCriteriaWhich page URLs should show chat. Check with isUrlAllowed.

Call getChatSettings() later to read them again, and isChatAvailable() for the current availability: { availability: 'online' | 'offline' | 'hidden' | 'disabled' }.

Build a minimal chat

custom-chat.js
let conversationId

KustomerCore.addListener('onMessageReceived', function (message) {
  if (message.conversationId !== conversationId) return
  render(message)
  KustomerCore.markRead({ conversationId })
})

KustomerCore.addListener('onAgentTypingActivity', function (activity) {
  showTyping(activity)
})

function startChat() {
  KustomerCore.createConversation({ title: 'Help with my order' }, function (conversation, error) {
    if (error) return showError(error)
    conversationId = conversation.conversationId
  })
}

function send(body) {
  KustomerCore.sendMessage({ conversationId, body }, function (message, error) {
    if (error) return showError(error)
    render(message)
  })
}

let typingTimer
function onInput() {
  KustomerCore.sendTypingActivity({ conversationId, typing: true })
  clearTimeout(typingTimer)
  typingTimer = setTimeout(function () {
    KustomerCore.sendTypingActivity({ conversationId, typing: false })
  }, 3000)
}

A message object looks like this:

Message
{
  "messageId": "6716a3b2c4e5f60012ab34cd",
  "conversationId": "6716a3a9c4e5f60012ab34c1",
  "body": "Your order shipped this morning.",
  "direction": "out",
  "createdAt": "2026-10-21T15:04:12.511Z",
  "attachments": [],
  "sentBy": { "type": "user", "id": "5f1b…", "displayName": "Ada", "avatarUrl": "https://…" },
  "isInAssistantMode": false
}

direction is in for the customer's messages and out for agents, assistants and automations.

Methods

Conversations

MethodParametersResponse
createConversation(params, cb)title (required), brand, assistant, lang, customThe conversation
getConversations(params, cb)page, pageSize, brandId{ conversations, pages }
getConversation({ conversationId }, cb)The conversation
endConversation({ conversationId }, cb)Ends it. Fires onConversationEnded.
describeConversation({ conversationId, customAttributes }, cb){ conversationId, custom }
handoff(params, cb)active, from, messages (at least one in and one out), brand, externalId, lang{ conversationId, ended, createdAt }. Imports a conversation that started elsewhere, such as in your own bot.

A conversation has conversationId, createdAt, lastMessageAt, preview, lastResponder (displayName, avatarUrl), ended, isInAssistantMode and custom.

Messages

MethodParametersResponse
sendMessage(params, cb)conversationId, body, attachments ([{ file: File }]), payload, langThe sent message
getMessages({ conversationId }, cb){ conversationId, messages, satisfaction }
getHistoricalMessages(params, cb)conversationId, count, beforeOlder messages, for scrolling back
markRead({ conversationId })Marks every unread message in the conversation read, including CSAT
getUnreadCount(){ total, conversations } (returned, not a callback)
sendTypingActivity({ conversationId, typing })Shows or hides the customer's typing indicator to agents
sendPresenceActivity({ presence })'online' or 'offline'Tells agents whether the customer is on the page

Attachments are browser File objects, for example from <input type="file">. Respect settings.disableAttachments.

Identity

MethodParametersResponse
login({ jwtToken }, cb)A JWT signed by your server{ identified, customerId, email, externalId }
isLoggedIn({ email } | { externalId }, cb)true or false
logout(cb)Clears the session from the browser
describeCustomer(params, cb)attributes (sharedEmails, sharedPhones, sharedSocials), customAttributes{ customerId, custom, sharedEmails, … }

See Customer identity for generating the JWT.

Knowledge base

MethodParametersResponse
getKnowledgeBaseConfig(cb)The brand's knowledge base settings
getCategories(params, cb)lang, knowledgeBaseId{ rootCategory, categories }
getArticles(params, cb)categoryId, lang, knowledgeBaseId{ articles }
getFeaturedArticles(params, cb)lang, knowledgeBaseIdFeatured articles
getArticleById(params, cb)articleId, lang, knowledgeBaseIdThe article
getArticleBySlug(params, cb)articleSlug, articleHash, lang, knowledgeBaseIdThe article
searchArticles(params, cb)term, lang, knowledgeBaseIdMatching articles
submitArticleFeedback(params, cb) / updateArticleFeedback(params, cb)Rating and written feedbackThe feedback

Articles have articleId, title, description, htmlBody, slug, lang, updatedAt and kbUrl. htmlBody is HTML from your knowledge base: sanitize it before inserting it into your page.

Satisfaction (CSAT)

MethodParameters
getTranslatedSatisfactionForm(params, cb)The CSAT form in the customer's language
submitSatisfactionForm(params, cb)satisfactionId, rating, answers, submittedAt, lang

When Kustomer sends a CSAT survey for a chat conversation, Core fires onSatisfactionReceived with it. getMessages also returns it as satisfaction.

Other

MethodPurpose
isUrlAllowed({ url }){ allowed }: whether chat should show on that URL under the brand's page rules
getChatSettings()The settings from init
isChatAvailable()Current availability
stop()Shut Core down

Events

Subscribe with KustomerCore.addListener(event, callback) and unsubscribe with removeListener(event, callback), passing the same function.

EventFires when
onConversationCreateA conversation is created
onMessageReceivedA message arrives from an agent, assistant or automation
onMessageSentThe customer's message is sent
onUnreadCountChangeUnread counts change
onAgentTypingActivityAn agent starts or stops typing
onConversationEndedA conversation ends
onConversationUnendedAn ended conversation is reopened
onAssistantEndedThe assistant finishes and the conversation moves on, usually to an agent
onSatisfactionReceivedA CSAT survey arrives
onConversationMergedTwo conversations are merged in Kustomer
onConversationDeletedA conversation is deleted in Kustomer
onCustomerDeleteThe customer is deleted in Kustomer
onSessionTitleChangedA conversation's title changes
onSessionCustomAttributesUpdatedA conversation's custom attributes change
onSessionOpenedA conversation is opened
onUrlPreviewReceivedA link preview is ready for a message
onLogin / onLogoutIdentity changes