SDK
SDK Reference
💬Get free consultation

SDK Reference

Who can use this feature?

  • Available to all users on any plan.
  • New to the SDK? Start with the SDK overview. For events, see SDK Events.

The SDK is the global object window.$chatty. This page lists every command it accepts.

Global objectwindow.$chatty
SDK version1.1.0, read at runtime with $chatty.version
InstallShips with the Chatty widget. Nothing extra to add.
Commands18 do actions, 13 set actions
Events22, documented on SDK Events

Methods

MethodReturnsDescription
push([verb, action, ...args])undefinedRun a command. Verbs: do, set, on, off.
on(event, callback)undefinedSubscribe to an event.
off(event, callback)undefinedUnsubscribe. Pass the same function reference used in on.
is(key)booleanSynchronously read a boolean state (see States).
get(key)valueSynchronously read a value (see Values).
versionstringSDK version, e.g. '1.1.0'.

No method returns a result and no method throws. A command that fails validation is dropped with a console warning. See Error handling.

on and off are also push verbs, so push(['on', event, cb]) is equivalent to on(event, cb). Before the widget bundle loads, push is the only method that exists, so the push form is the safe one to use at the top of a page.


Command format

A command is an array: the verb, the action name, then the arguments.

window.$chatty.push(['do', 'message:send', 'text', 'I need help'])

The arguments can also be wrapped in a single array. Both forms below are identical:

window.$chatty.push(['set', 'prechat:field', 'name', 'Jane Doe'])
window.$chatty.push(['set', 'prechat:field', ['name', 'Jane Doe']])

An array with fewer than two entries, an unknown verb, or an unknown action name is dropped with a console warning.


do actions

Run with push(['do', action, ...args]). Eighteen actions in six groups.

Widget visibility

ActionArgumentsRequiredDescription
chat:openNoneOpen the chat window.
chat:closeNoneClose the chat window, back to the launcher.
chat:toggleNoneOpen if closed, close if open.
chat:showNoneShow the widget again after chat:hide.
chat:hideNoneHide the whole widget, both the launcher and the window.
launcher:showNoneShow only the launcher button.
launcher:hideNoneHide only the launcher button.
window.$chatty.push(['do', 'chat:open'])
window.$chatty.push(['do', 'launcher:hide'])

chat:toggle decides from the state the widget last reported, the same value is('chat:opened') returns.

launcher:show and launcher:hide do not change is('chat:visible'), which tracks only chat:show and chat:hide. There is no state key for launcher visibility on its own.

Messaging

ActionArgumentsTypeRequiredDescription
message:sendtypestringYesMust be 'text'. Any other value is rejected.
contentstringYesThe message body. 1 to 5,000 characters, no HTML.
typing:setactivebooleanYesShow or clear the visitor's typing indicator. A non-boolean is rejected.
window.$chatty.push(['do', 'message:send', 'text', 'I need help with my order'])
window.$chatty.push(['do', 'typing:set', true])

The SDK cannot send attachments or rich content. 'text' is the only message type.

If a required pre-chat form is on screen, message:send is held and delivered as the first message as soon as the form is submitted. Only the most recent held message survives, so a second call replaces the first.

message:send is rate limited at 15 per minute and one per second. typing:set is limited to 30 calls per minute, and only calls with active set to true count against it.

Identity and session

ActionArgumentsTypeRequiredDescription
identifyfieldsobjectYesSet visitor identity in one call.
logoutNoneClear the identity, the pre-chat prefill, the commerce context, and the stored session, then start a new conversation.
session:resetNoneEnd the current conversation and start a new one. Also clears the identity and the pre-chat prefill.

identify accepts these fields, all optional on their own, but at least one has to be valid or the whole call is dropped:

FieldTypeDescription
emailstringMust look like an email address. Trimmed and lowercased before use.
namestringNon-empty, no HTML.
phonestringNon-empty, no HTML.
attributesobjectStructured attributes about the visitor.
window.$chatty.push(['do', 'identify', {
  email: '[email protected]',
  name: 'Jane Doe',
  phone: '+15550134',
  attributes: { plan: 'gold' }
}])

Invalid fields are dropped one by one, not as a group. An identify call with a malformed email and a valid name still applies the name.

identify and the matching set user:* actions write to the same visitor record and merge, so use whichever fits your code. Use identify for a single call at page load, and set when values arrive at different times. The one difference: the per-field limits in Limits and validation are enforced by the set actions, while identify checks format only.

!

The difference between logout and session:reset is what happens to the visitor's stored session. logout clears it, so the next conversation cannot be linked back to the previous one. session:reset leaves it in place. Call logout when the shopper signs out of your store, and session:reset when you only want a clean conversation.

!

Identity passed from the browser is supplied by the page, not verified by Chatty. Treat it as a convenience for your support team, not as proof of who the visitor is. Do not use it to gate anything sensitive. See Security and trust boundary.

Conversation control

ActionArgumentsTypeRequiredDescription
escalateNoneAsk for a human agent. This is the AI to human handoff.
trigger:runcampaignIdstringYesRun a chat campaign by ID. 1 to 200 characters.
article:showarticleIdstringYesOpen an FAQ article inside the widget. 1 to 200 characters.
window.$chatty.push(['do', 'escalate'])
window.$chatty.push(['do', 'article:show', 'ARTICLE_ID'])

Both IDs must be strings. A number is rejected before it reaches the widget, so wrap it: String(articleId).

escalate does nothing when the conversation is already with a human agent, or when no conversation exists yet. When it does run, it posts a visible message into the conversation on the visitor's behalf and takes the conversation out of AI mode. It does not pick an agent: the conversation still has to be assigned, by your assignment rules or by hand.

trigger:run and article:show are matched against the campaigns and articles the widget has already loaded. An ID it does not recognise is logged as a [ChattySDK] warning and nothing opens.

Pre-chat form

Available from SDK 1.1.0.

ActionArgumentsRequiredDescription
prechat:submitNoneSubmit the form using the values you prefilled.
prechat:skipNoneSkip the form and chat anonymously, when the shop allows skipping.
if (window.$chatty.is('prechat:visible') && !window.$chatty.is('prechat:required')) {
  window.$chatty.push(['do', 'prechat:skip'])
}

prechat:submit submits the values you set with set prechat:field, not whatever the visitor typed into the form. Prefill the fields first.

It checks only the fields the shop marked required, which can be name and email. Phone is never required. A missing required field cancels the submission and logs a warning.

Skipping is not submitting: prechat:skip emits no prechat:submitted and no email:captured event.

Custom event tracking

ActionArgumentsTypeRequiredDescription
event:tracknamestringYesEvent name, 1 to 200 characters.
dataobjectNoUp to 20 keys. String, number, and boolean values only.
window.$chatty.push(['do', 'event:track', 'viewed_size_guide', { product: 'shirt-101' }])

data must be a plain object. An array is discarded entirely, and inside the object any value that is not a string, number, or boolean is dropped key by key. Keys past the twentieth are dropped, and string values longer than 1,000 characters are truncated rather than rejected.

Every tracked event is also re-dispatched on the page as a DOM CustomEvent named chatty:event. See Custom events you raise yourself.


set actions

Run with push(['set', action, value]). Thirteen actions.

Composer and visitor data

ActionValueTypeDescription
message:texttextstringPrefill the input box without sending. The visitor can still edit it.
user:emailemailstringVisitor email. Must look like an email address.
user:namenamestringVisitor name. Non-empty, no HTML.
user:phonephonestringVisitor phone. Non-empty, no HTML.
user:attributesattributesobjectStructured attributes about the visitor. Merges across calls.
user:contextcontextobjectFree-form context shown to your team and the AI. Merges across calls.
shop:datadataobjectFree-form context about the shop or page. Merges across calls.
conversation:attributeslistarrayNamed pairs stored on the conversation, as [{name, value}].
window.$chatty.push(['set', 'message:text', 'I want to know about shipping'])
window.$chatty.push(['set', 'user:email', '[email protected]'])
window.$chatty.push(['set', 'user:context', { vipLevel: 3, accountAge: '2 years' }])

user:context, shop:data, and user:attributes merge rather than replace, so you can add keys as the page learns more. Values must be a string, number, or boolean; anything else is dropped silently.

conversation:attributes replaces the previous list rather than merging. Each entry needs a non-empty name and a non-empty value; both are converted to text, and an entry missing either one is dropped.

set user:email has a side effect worth knowing: it also prefills the pre-chat form's email field, so a visitor who reaches the form sees the address already filled in.

Commerce context

Give the AI assistant structured context about what the visitor is looking at.

ActionValueTypeDescription
productproductobjectThe product currently being viewed.
cartcartobjectThe current cart.
orderorderobjectThe order being discussed.
window.$chatty.push(['set', 'product', { id: 123, title: 'Steel Door', price: '499.00' }])
window.$chatty.push(['set', 'cart', { items: 2, total: '648.00' }])
window.$chatty.push(['set', 'order', { name: '#1042', status: 'shipped' }])

Each object must survive a round trip through JSON and stay under 8,000 characters once serialized. An oversized object is rejected whole, not truncated, so nothing is set at all. The three keys are independent: setting cart leaves product and order untouched.

Read the merged result back with $chatty.get('commerce:context'). do logout clears all three.

Locale

ActionValueTypeDescription
localelocalestringLanguage hint for the conversation. 1 to 35 characters.
window.$chatty.push(['set', 'locale', 'de'])

This is a hint that applies to the current conversation, not a switch. It takes effect only once a conversation exists, and it does not force the language the AI replies in. The assistant answers in the language the visitor writes in.

Pre-chat prefill

Available from SDK 1.1.0. Takes a field name and a value, so this is the one set action with two arguments.

FieldTypeLimit
namestring1 to 150 characters, no HTML
emailstringMust look like an email address, up to 254 characters
phonestring1 to 50 characters, no HTML
messagestring1 to 5,000 characters, no HTML
window.$chatty.push(['set', 'prechat:field', 'name', 'Jane Doe'])
window.$chatty.push(['set', 'prechat:field', 'email', '[email protected]'])
window.$chatty.push(['set', 'prechat:field', 'phone', '+15550134'])
 
// 'message' is queued and sent automatically once the form is submitted
window.$chatty.push(['set', 'prechat:field', 'message', 'Where is my order #1042?'])

Any other field name is rejected with a warning.

message behaves differently from the other three. It is not a form field: it is held as the first message and sent once the form is submitted. It shares that slot with a held do message:send, so the last of the two wins.

Prefills are sticky, so they apply even if the form appears later in the session. do logout and do session:reset clear them.


States

Read synchronously with is(key)boolean. An unknown key returns false with no warning, so check your spelling.

KeyTrue when
chat:openedThe chat window is open.
chat:closedThe chat window is closed. The exact opposite of chat:opened.
chat:visibleThe widget has not been hidden with chat:hide. Starts true.
session:ongoingA conversation exists, which is true from the visitor's first message onward.
prechat:visibleThe pre-chat form is on screen.
prechat:requiredThe pre-chat form must be completed before chatting.
agent:onlineSupport is within chat hours.
if (window.$chatty.is('chat:opened')) {
  window.$chatty.push(['do', 'chat:close'])
}

These values mirror what the widget last reported. Read them from an event handler rather than at the top of the page, where the widget may not have reported anything yet.


Values

Read synchronously with get(key). An unknown key returns null.

KeyReturnsBefore the widget reports
message:textCurrent text in the composer, as a string.''
session:identifierThe conversation ID.null
chat:unread:countUnread messages for the visitor, as a number.0
prechat:config{ mode, preChatFields, requiredName, requiredEmail, required }null
commerce:contextThe merged product, cart, and order objects.{}
const unread = window.$chatty.get('chat:unread:count')

prechat:config fields: mode is the shop's pre-chat setting, preChatFields is the list of fields the form shows, requiredName and requiredEmail say which of them the visitor must fill in, and required is true when the form cannot be skipped.


Limits and validation

The SDK enforces limits to keep the widget responsive and to prevent abuse. Values marked truncated are shortened and still applied; everything else is rejected outright.

InputLimitOver the limit
message:send15 per minute, 1 second apart, 1 to 5,000 characters, no HTMLRejected
typing:set30 calls per minute, counting only trueRejected
event:track name1 to 200 charactersRejected
event:track data20 keys, 1,000 characters per value, string / number / boolean onlyExtra keys dropped, values truncated
trigger:run / article:show ID1 to 200 characters, string onlyRejected
user:emailValid email, up to 254 charactersRejected
user:name1 to 150 characters, no HTMLRejected
user:phone1 to 50 characters, no HTMLRejected
user:context / shop:data / user:attributes50 keys, 2,000 characters per value, string / number / boolean onlyExtra keys dropped, values truncated
product / cart / orderPlain JSON, 8,000 characters each once serializedRejected whole
conversation:attributes50 entries, name up to 255 characters, value up to 1,000 charactersExtra entries dropped, values truncated
locale1 to 35 charactersRejected
prechat:field name / phone / message150 / 50 / 5,000 characters, no HTMLRejected

"No HTML" means the value is rejected if it contains anything that looks like a tag.


Error handling

Commands never throw. A command that fails validation or hits a rate limit is dropped, and the SDK logs a warning prefixed with [ChattySDK] to the browser console.

window.$chatty.push(['set', 'user:email', 'not-an-email'])
// [ChattySDK] ... the command is ignored, execution continues

Three consequences worth designing around:

  • There is no error callback and no return value. Your code cannot detect a rejected command at runtime, so validate input on your side before pushing it, especially anything coming from a form or a URL parameter.
  • A dropped command is silent to the visitor. If a rate limit swallows a message:send, nothing appears in the chat. Throttle on your side rather than relying on the SDK to queue.
  • Not every no-op logs a warning. A command that passes validation but arrives before the part of the widget that handles it has rendered is simply not acted on, with nothing in the console. See When your commands run.

Security and trust boundary

The SDK runs entirely in the visitor's browser. Everything below follows from that.

Identity is not verified. identify and the set user:* actions take whatever the page gives them. Anyone can open the browser console and pass another person's email. Chatty uses these values to label the conversation for your team, so:

  • Do not use SDK identity to unlock account data, order details, or anything else you would gate behind a login.
  • Do not treat a matching email in your inbox as proof of identity.

A signed variant of identify, where your server vouches for the email, exists in the product but is not open to stores yet. Until it is, treat every identity the page supplies as unverified.

Input is sanitised. All text is sanitised before it reaches the widget. HTML and script content is rejected, and the fields marked "no HTML" above reject markup outright.

Only documented keys are exposed. is and get return the keys listed on this page. The SDK object does not expose the widget's internal state, and its methods are frozen so ordinary scripts on the page cannot replace them by accident. This is a guard against collisions with other scripts, not a defence against a hostile script. Any script on your storefront runs with the same privileges as your own code.

Anything you push is visible to the visitor. user:context, shop:data, and the commerce objects sit in page memory. Pass what your support team needs to help, and nothing more: no internal costs, margins, risk scores, or notes you would not show the customer.


What the SDK cannot do

  • Read past conversations or message history. There is no getter for it.
  • Send attachments, images, or rich content. message:send is text only.
  • Reply as an agent, or act on behalf of your team.
  • Change widget settings, colours, or position. Those live in your dashboard.
  • Embed the widget. The SDK controls a widget that Chatty already loaded; it is not an npm package.

For server-side access to conversations, see the Chat Conversations API.


Browser support

Chrome 80+, Firefox 72+, Safari 13.1+, Edge 80+. The SDK ships as modern JavaScript and does not include a transpiled fallback for older browsers.


Changelog

VersionChanges
1.1.0Added pre-chat form control: set prechat:field, do prechat:submit, do prechat:skip, and the prechat:visible / prechat:required states with get prechat:config.
1.0.0Initial release.

Check the version at runtime before calling a newer API:

window.$chatty.on('sdk:ready', () => {
  const [major, minor] = window.$chatty.version.split('.').map(Number)
 
  if (major > 1 || (major === 1 && minor >= 1)) {
    window.$chatty.push(['set', 'prechat:field', 'email', '[email protected]'])
  }
})

Compare the parts as numbers, not the whole string. In a string comparison '1.9.0' >= '1.10.0' is true, which is wrong.


Troubleshooting

window.$chatty is undefined. The widget script has not loaded on that page. Check that the Chatty app embed is enabled in your theme and that the page is not excluded. Starting your code with window.$chatty = window.$chatty || [] makes it safe regardless of load order.

window.$chatty.on is not a function. The widget bundle has not loaded yet, so window.$chatty is still the plain array you created. Only push exists at that point. Use push(['on', event, cb]) instead.

chat:open does nothing. The widget may still be initialising, so wait for sdk:ready. It may also have been hidden earlier by chat:hide, in which case call chat:show first.

message:send seems ignored. Check the console for a [ChattySDK] rate-limit or validation warning. If a required pre-chat form is open, the message is held and sent once the form is submitted. If nothing at all appears in the console, the chat window had probably not rendered yet.

article:show or trigger:run does nothing. Check the console. [ChattySDK] article:show — expects an article id means you passed a number or an empty value. unknown article id means the widget has no article with that ID loaded.

A handler runs twice. You are probably subscribed to message:received and to ai:reply or human:reply at the same time. See Avoiding duplicate handling.


Need help?

If a command still is not working, confirm the widget is loading on the page. window.$chatty should be defined and window.$chatty.version should return '1.1.0'. Still stuck? Contact the Chatty support team from your dashboard, and include the [ChattySDK] console warnings you see. For server-side access, see the Chat Conversations API.