SDK
Overview
💬Get free consultation

Storefront SDK

Who can use this feature?

  • Available to all users on any plan.
  • Requires a developer to add JavaScript to your storefront theme.

Overview

The Chatty Storefront SDK is a small JavaScript API for controlling the Chatty chat widget from your store's pages. With it you can open or close the chatbox, prefill or send a message, pass customer and shop context, hand the conversation to a human, prefill the pre-chat form, track custom events, and react to what the visitor is doing in chat.

It's the right tool when you want the widget to respond to your own buttons, flows, or page logic. For example, you can open chat from a "Need help?" link, or pre-fill a message from a product page.

Three pages cover it: this guide, the SDK Reference for all 31 commands, and SDK Events for all 22 events.


How it works

The SDK is exposed on the page as window.$chatty. It uses a buffered command queue: you push commands as [verb, action, ...args] tuples, and they run as soon as the widget is ready, so you can call it even before the widget has finished loading.

// Open the chatbox
window.$chatty.push(['do', 'chat:open'])

The four verbs are:

VerbWhat it does
doPerform an action (open, close, send…).
setSet a value (prefill text, customer context…).
onSubscribe to an event.
offUnsubscribe from an event.

The current SDK version is 1.1.0. Read it at runtime with window.$chatty.version.


Install

The SDK ships with the Chatty widget. Once Chatty is installed on your store, window.$chatty is available automatically. There's nothing extra to install.

Check the widget is live on your storefront first. SettingsGeneralEmbed app shows whether Chatty is enabled in your theme, and turns it on if it isn't.

If you want to queue commands before the widget bundle finishes loading, add this bootstrap snippet near the top of your theme (optional but recommended):

<script>
  window.$chatty = window.$chatty || [];
</script>

Any commands you push before the widget loads are buffered and replayed in order once it's ready.

!

The SDK controls a widget that's already on the page. It is not an npm package and does not embed Chatty by itself. Install the Chatty app first so the widget loads on your storefront.


When your commands run

The widget loads in stages, and which stage you are in decides what works. Getting this wrong is the most common reason a command appears to do nothing.

Before the widget bundle loads

window.$chatty is the plain array from the bootstrap snippet. push is the only method that exists. Calling on, is, get, or reading version at this point throws a TypeError.

window.$chatty = window.$chatty || [];
 
window.$chatty.push(['on', 'sdk:ready', function () { /* safe */ }])
window.$chatty.on('sdk:ready', function () { /* TypeError */ })

Everything you push into the array is replayed in order once the bundle arrives, so pushing early costs you nothing.

When the SDK is ready

sdk:ready fires once the command layer is live. From that point on, off, is, and get all work, and subscribing to sdk:ready after it has already fired still runs your callback immediately. You never need to poll.

window.$chatty.push(['on', 'sdk:ready', function () {
  // window.$chatty is the real SDK from here on
}])

When the chat window has rendered

sdk:ready means commands are accepted. It does not mean the chat window exists on screen yet.

Context you set is remembered and applied whenever the widget catches up, so it is safe to set at page load: identify, every set user:* action, set product / cart / order, set conversation:attributes, and set prechat:field.

set locale is the exception. It only lands once a conversation exists, and a value set before that is dropped rather than held, so send it after conversation:started.

Actions that drive the chat window are delivered once, to whoever is listening at that moment: message:send, set message:text, session:reset, event:track, escalate, article:show, trigger:run, prechat:submit, and prechat:skip. Send them after the window is open, not at page load. Nothing is logged when one of these arrives too early.

// Robust: open first, act once the window reports itself open
function askAboutReturns() {
  function onOpen() {
    window.$chatty.off('chat:opened', onOpen)
    window.$chatty.push(['do', 'message:send', 'text', 'What is your returns policy?'])
  }
  window.$chatty.on('chat:opened', onOpen)
  window.$chatty.push(['do', 'chat:open'])
}

Quick start

Open the chatbox from a button

<button onclick="window.$chatty.push(['do', 'chat:open'])">
  Need help? Chat with us
</button>

Prefill and send a message

// Prefill the input without sending
window.$chatty.push(['set', 'message:text', 'I have a question about my order'])
 
// Or send it immediately
window.$chatty.push(['do', 'message:send', 'text', 'Is the Daris Tee back in stock?'])

Pass who the customer is

window.$chatty.push(['set', 'user:email', '[email protected]'])
window.$chatty.push(['set', 'user:context', { plan: 'vip', orders: 4 }])

Fill in the pre-chat form ahead of time

// Sticky, applied even if the form appears later
window.$chatty.push(['set', 'prechat:field', 'name', 'Jane Doe'])
window.$chatty.push(['set', 'prechat:field', 'email', '[email protected]'])

React when a reply arrives

window.$chatty.on('message:received', (data) => {
  console.log('Agent replied:', data.text)
})

Recipes

Custom "Chat with us" button

<button onclick="window.$chatty.push(['do', 'chat:open'])">Chat with us</button>

Open chat with a question already typed

set message:text reaches the composer only once the chat window has rendered, so prefill from the chat:opened handler rather than in the same click.

<button onclick="askAboutReturns()">Ask about returns</button>
 
<script>
  function askAboutReturns() {
    function onOpen() {
      window.$chatty.off('chat:opened', onOpen)
      window.$chatty.push(['set', 'message:text', 'What is your returns policy?'])
    }
    window.$chatty.on('chat:opened', onOpen)
    window.$chatty.push(['do', 'chat:open'])
  }
</script>

Hide the widget on specific pages

if (window.location.pathname.startsWith('/pages/legal')) {
  window.$chatty.push(['do', 'chat:hide'])
}

Identify logged-in customers (Shopify Liquid)

{% if customer %}
<script>
  window.$chatty = window.$chatty || [];
  window.$chatty.push(['do', 'identify', {
    email: {{ customer.email | json }},
    name: {{ customer.name | json }}
  }]);
</script>
{% endif %}

Pass the product the visitor is looking at

{% if product %}
<script>
  window.$chatty = window.$chatty || [];
  window.$chatty.push(['set', 'product', {
    id: {{ product.id | json }},
    title: {{ product.title | json }},
    price: {{ product.price | money_without_currency | json }}
  }]);
</script>
{% endif %}

Hold the widget until the visitor accepts cookies

Useful where consent is required before loading third-party chat.

window.$chatty = window.$chatty || [];
window.$chatty.push(['do', 'chat:hide'])
 
// Call this from your consent banner's "accept" handler
function onConsentGiven() {
  window.$chatty.push(['do', 'chat:show'])
}

Common mistakes

  • Calling on before the bundle loads. Use push(['on', event, cb]) at the top of a page. See When your commands run.
  • Passing a number as an ID. do article:show and do trigger:run take strings only. A numeric ID is dropped.
  • Expecting identify to prove who the visitor is. Anyone can send any email from the console. See Before you ship.
  • Counting a lead twice. prechat:submitted and conversation:started both fire for one visitor on a shop with a required pre-chat form. Pick one.
  • Handling a reply twice. Subscribe to message:received, or to the ai:reply and human:reply pair, never both.
  • Confusing logout with session:reset. Both start a fresh conversation and clear the identity. Only logout clears the visitor's stored session, which is what you want when the shopper signs out.
  • Reading is() and get() at page load. They mirror what the widget last reported, so read them from an event handler.

Before you ship

Customer details you pass from the browser are supplied by the page, not verified by Chatty. Anyone can open the console and send a different email. Use them to give your support team context, never to unlock account or order data. See Security and trust boundary before you wire identify into your theme.

Check the console on a real storefront page too. Every rejected command logs a [ChattySDK] warning, and those warnings are the only signal you get that something was dropped.


See the full SDK Reference for every command, argument, state, and limit, and SDK Events for every event and its payload.