1. Docs
  2. Developers

JavaScript API

Control the TalkingDot messenger from your own code: identify logged-in users, open it from your own buttons, prefill messages, track events and react to unread replies.

Load the messenger

The simplest install is one script tag. Replace WORKSPACE_KEY with the key shown in Settings → Install.

HTML
<script src="https://talkingdot.com/widget.js" data-key="WORKSPACE_KEY" async></script>

When the script has loaded it defines one global function, TalkingDot(). Every command on this page is a call to it: the first argument is the command name and the rest are that command's arguments, for example TalkingDot('open') or TalkingDot('track', 'signed_up').

Pass settings and queue calls with the async loader

To tell the messenger who is logged in, or to call TalkingDot() before the script has finished downloading, set window.TalkingDotSettings and load the script with this small loader instead. The loader defines a stub TalkingDot() that queues your calls; the messenger runs them, in order, as soon as it loads.

HTML
<script>
  window.TalkingDotSettings = {
    key: 'WORKSPACE_KEY',
    hide_default_launcher: false
  };

  (function(w,d){w.TalkingDot=w.TalkingDot||function(){(w.TalkingDot.q=w.TalkingDot.q||[]).push(arguments)};var s=d.createElement('script');s.async=1;s.src='https://talkingdot.com/widget.js';s.setAttribute('data-key','WORKSPACE_KEY');d.head.appendChild(s)})(window,document);

  // Safe to call straight away: queued until the messenger has loaded.
  TalkingDot('onReady', function () {
    console.log('Messenger ready');
  });
</script>

Why the loader: with the plain script tag, TalkingDot doesn't exist until the file has downloaded, so calling it earlier throws a ReferenceError. With the loader you can call TalkingDot() from anywhere on the page, at any time.

window.TalkingDotSettings must be set before the messenger script runs. Using a framework or a tag manager? See React & Next.js, Vue & Nuxt and Google Tag Manager.

Settings keys

These keys are read from window.TalkingDotSettings and from the settings object you pass to TalkingDot('boot', settings). The identity keys can also be sent later with TalkingDot('update', …).

KeyTypeDescription
keystringYour workspace key from Settings → Install. Only needed when the script tag has no data-key attribute.
user_idstringYour own ID for the logged-in user. It's stored as the contact's external_id and turns the contact into a user.
emailstringThe user's email address.
namestringThe user's full name, shown to your team in the Inbox.
phonestringPhone number.
companystringCompany or organisation name.
avatar_urlstringAn https:// URL of the user's picture.
user_hashstringThe HMAC signature that proves the identity came from your server. See Identity verification.
hide_default_launcherbooleantrue hides the round launcher button so you can open the messenger from your own UI.
any other keystring, number or booleanSaved on the contact as a custom attribute, for example plan: 'pro'.

Commands

Every command is called as TalkingDot('command', …arguments).

CommandArgumentsWhat it does
bootsettings (object)Starts the messenger with these settings (same keys as TalkingDotSettings). Use it when the page loads the script without a key, or queue it with the loader so it runs before the messenger starts. Once the messenger is running it has no effect: use update.
updatedata (object)Updates the current person: identity keys (user_id, email, name, phone, company, avatar_url, user_hash) and custom attributes. Called before the messenger has started, the values are merged into its settings.
open / shownoneOpens the messenger.
close / hidenoneCloses the messenger.
togglenoneOpens the messenger if it's closed, closes it if it's open.
showNewMessagetext (string, optional)Opens the messenger on a new conversation with the composer prefilled with text. The visitor still presses send.
showMessagesnoneOpens the messenger on the visitor's list of conversations.
showArticlearticleId (number)Opens a help-center article inside the messenger.
showSpace'home', 'messages' or 'help'Opens the messenger on its home screen, the conversation list or the help-center search.
trackname (string), meta (object, optional)Records an event on the contact, for example 'invoice_paid'. See Track events.
shutdownnoneLogs the visitor out: forgets the current visitor in this browser and starts again as a new, anonymous visitor. Call it when your user logs out.
hideLaunchernoneHides the default launcher button.
showLaunchernoneShows the default launcher button again.
onUnreadCountChangefn(count)Calls fn with the number of unread replies straight away, then every time it changes.
onOpenfn()Calls fn whenever the messenger opens.
onClosefn()Calls fn whenever the messenger closes.
onReadyfn()Calls fn once the messenger has started (immediately, if it already has).
getVisitorIdnoneReturns the current contact's ID, the same id the REST API uses. Returns 0 until the messenger has started, so call it inside onReady.

Tip: run the commands that change what the messenger shows (showNewMessage, showMessages, showArticle, showSpace) once the messenger is ready: from a click handler, or inside TalkingDot('onReady', …). open can be called at any time; it waits until the messenger is ready.

Use your own launcher button

Hide the default launcher with hide_default_launcher: true, open the messenger from any element with TalkingDot('open'), and use onUnreadCountChange to show an unread badge.

HTML
<button type="button" id="support-button">
  Support <span id="support-badge" hidden>0</span>
</button>

<script>
  window.TalkingDotSettings = {
    key: 'WORKSPACE_KEY',
    hide_default_launcher: true
  };

  (function(w,d){w.TalkingDot=w.TalkingDot||function(){(w.TalkingDot.q=w.TalkingDot.q||[]).push(arguments)};var s=d.createElement('script');s.async=1;s.src='https://talkingdot.com/widget.js';s.setAttribute('data-key','WORKSPACE_KEY');d.head.appendChild(s)})(window,document);

  document.getElementById('support-button').addEventListener('click', function () {
    TalkingDot('open');
  });

  TalkingDot('onUnreadCountChange', function (count) {
    var badge = document.getElementById('support-badge');
    badge.textContent = count > 9 ? '9+' : String(count);
    badge.hidden = count === 0;
  });
</script>

To switch the default launcher on and off later (for example, only on some screens of an app), call TalkingDot('hideLauncher') and TalkingDot('showLauncher').

Identify logged-in users

When someone is logged in to your site or app, pass who they are so your team sees their name and email in the Inbox, and so their conversations follow them across browsers and devices. Print the values into the page on your server:

HTML
<script>
  window.TalkingDotSettings = {
    key: 'WORKSPACE_KEY',
    user_id: '42',                   // your own ID for this user
    email: 'ada@example.com',
    name: 'Ada Lovelace',
    company: 'Analytical Engines Ltd',
    user_hash: '61cb1b052b30852a660424f8e2a1c4f90996a934e09cf1aafeb174b5bae47efe',
    plan: 'pro'                      // extra keys become custom attributes
  };
</script>
<script src="https://talkingdot.com/widget.js" data-key="WORKSPACE_KEY" async></script>

In a single-page app where the user logs in without a page load, send the same keys with update once your login request succeeds:

JavaScript
// identity = { user_id, email, name, user_hash }, built by your server
fetch('/account/chat-identity', { credentials: 'same-origin' })
  .then(function (response) { return response.json(); })
  .then(function (identity) {
    TalkingDot('update', identity);
  });

Always send a user_hash. Anything in the page can be changed from the browser console, so without a signature anyone could claim to be another user. Compute the hash on your server and turn on Require identity verification in Settings → Security. The full guide, with code for PHP, Node.js, Python and Ruby, is in Identity verification.

Custom attributes

Any extra key you add to TalkingDotSettings, boot or update whose value is a string, number or boolean is saved on the contact as a custom attribute. Use them for the facts your team needs while helping someone: plan, account ID, signup date, number of seats.

JavaScript
TalkingDot('update', {
  plan: 'pro',
  seats: 5,
  trial: false,
  signup_date: '2026-09-14'
});
  • Attributes are merged: the keys you send are added or overwritten and other attributes are kept. Send an empty string ('') to remove one.
  • Objects and arrays are ignored. Flatten them into separate keys, for example billing_country: 'GB'.
  • Key names can use letters, numbers, spaces, _ and - (other characters are dropped) and are cut to 50 characters. String values are cut to 500 characters. A contact keeps up to 100 attributes.
  • Attributes appear in the contact sidebar in the Inbox and as custom_attributes in the REST API, where your server can also set them with PATCH /api/v1/contacts/{id}.
  • Values set in the browser can be changed by the visitor, and your team can see them. Don't use them for secrets or for anything you rely on for security.

Track events

Record what people do in your product so your team can see it in the contact's sidebar, alongside their conversations:

JavaScript
TalkingDot('track', 'invoice_paid', {
  invoice: 'INV-1042',
  amount: 49,
  currency: 'EUR'
});
  • Event names can use letters, numbers, spaces and . _ - :, up to 80 characters. Pick a consistent style such as snake_case.
  • meta is optional and holds up to 20 flat values (strings, numbers or booleans). String values are cut to 255 characters.
  • Events tracked before the messenger is ready are sent as soon as it is. Each visitor can send up to 60 events a minute.
  • To record events from your server instead, use POST /api/v1/contacts/{id}/events in the REST API.

Log users out

The messenger remembers the visitor in the browser's localStorage. When your user logs out, call shutdown so the next person who uses the same browser doesn't see their conversations:

JavaScript
document.getElementById('logout-button').addEventListener('click', function () {
  TalkingDot('shutdown');
  // ...then run your normal logout, e.g. submit the logout form
});

shutdown signs the visitor out on the server too, and the request still completes if the page navigates away straight after. The messenger then restarts as a new, anonymous visitor. Their conversations aren't deleted: they come back when the user logs in again and is identified with the same user_id.

Open an article, a space or a prefilled message

Link parts of your interface straight to the right place in the messenger:

JavaScript
// "How do refunds work?" link: open help-center article 64 in the messenger
document.getElementById('refund-help').addEventListener('click', function (event) {
  event.preventDefault();
  TalkingDot('showArticle', 64);
});

// "Ask about annual billing" button: open a new conversation with text ready to send
document.getElementById('annual-question').addEventListener('click', function () {
  TalkingDot('showNewMessage', 'Hi! Can I switch my plan to annual billing?');
});

// "My conversations" link in your account menu
document.getElementById('my-conversations').addEventListener('click', function (event) {
  event.preventDefault();
  TalkingDot('showSpace', 'messages');
});

An article's ID is the number at the start of the last part of its public URL: in https://talkingdot.com/help/acme/articles/64-how-refunds-work the ID is 64. You can also list articles and their IDs with GET /api/v1/articles. See the Help center guide for writing articles.

React to the messenger

Use the callbacks to keep your own UI in step with the messenger, or to send its activity to your analytics:

JavaScript
TalkingDot('onOpen', function () {
  document.body.classList.add('chat-open');
});

TalkingDot('onClose', function () {
  document.body.classList.remove('chat-open');
});

TalkingDot('onReady', function () {
  // The contact ID matches /api/v1/contacts/{id} in the REST API.
  var contactId = TalkingDot('getVisitorId');
  console.log('Chat contact', contactId);
});

You can register as many callbacks as you like; they run in the order you added them.

Google Analytics & Tag Manager events

Turn on Settings → Messenger → Send messenger events to Google Analytics and the messenger reports what visitors do — no code needed. When your page has Google Tag Manager, each event is pushed to window.dataLayer; when it has the Google tag (gtag.js), it is also sent with gtag('event', …). Sites without either are not affected.

EventWhenParameters
talkingdot_openThe visitor opens the messenger—
talkingdot_conversation_startedTheir first message starts a conversation—
talkingdot_message_sentThe visitor sends a message—
talkingdot_email_capturedThe visitor leaves their emailsource: popup, pre_chat or messenger; popup_name for popups
talkingdot_popup_viewA popup appearspopup_id, popup_name, popup_type (modal, corner, bar or messenger)
talkingdot_popup_clickIts “Start a chat” or link button is clicked
talkingdot_popup_submitSomeone signs up or answers a survey

Google Tag Manager: create a Custom Event trigger for each event name you care about (or one trigger with the regex ^talkingdot_) and fire a GA4 event tag from it. Use Data Layer Variables for popup_name and source. gtag.js: the events arrive in GA4 automatically; mark talkingdot_email_captured or talkingdot_popup_submit as a key event to count leads. If your site loads both and GTM already forwards these events to GA4, skip the GTM tag so they are not counted twice.

Prefer to handle it yourself? The callbacks above still work with the setting off.

Single-page apps

You don't need to do anything when the URL changes in a single-page app. The messenger watches the history API (pushState, replaceState and the back and forward buttons) and records each new page view on its own, so your page-based show/hide rules and proactive messages keep working as people move around.

Load the script once, in your app shell, not on every route. Call update after login and shutdown after logout, as shown above.

Next steps

  • Identity verification: sign user_id and email so nobody can impersonate your users.
  • REST API: manage contacts, conversations and articles from your server.
  • Webhooks: get notified on your server when conversations and contacts change.
Last updated October 4, 2026 Something unclear? Tell us