message.comDevelopers

JavaScript API Live

Once the bundle loads, a global window.Message object is exposed. It gives you imperative control over the launcher, the visitor identity, the message stream, and the event bus.

Wait for ready

The bundle is async, so window.Message is not available immediately. If your code runs at the top of the page, use the MessageOnReady hook. It fires exactly once, after the bundle has booted and the public config has loaded.

JavaScript
// Code that runs before the bundle has finished loading
// can use the global MessageOnReady hook.
window.MessageOnReady = function () {
  window.Message.identify({ email: '[email protected]' });
  window.Message.open();
};

Inside a React or Vue component that mounts after page load, window.Message is reliably present. The ready hook matters mostly for inline scripts that run during page parsing.

Core methods

Every method on Message is synchronous from the caller's point of view. Network calls happen on a queue under the hood; if you call identify before the socket connects, the call is buffered and replays once ready.

JavaScript
// Show / hide the launcher and panel
Message.open();
Message.close();
Message.toggle();

// Identify a visitor. Links chats across sessions.
Message.identify({
  email: '[email protected]',
  name: 'Alice Johnson',
  userId: 'crm-4567',
  createdAt: 1714000000,  // unix seconds
  // arbitrary custom attributes (string / number / bool)
  plan: 'pro',
  mrr: 99
});

// Send a programmatic visitor message
Message.sendMessage("Hi, I need help with my order");

// Update workspace context without re-identifying
Message.update({ pageUrl: location.href, route: '/checkout' });

// Push a custom event the dashboard and AI can see
Message.track('checkout_started', { cartValue: 129.95 });

// Sign out the visitor (clears local conversation state)
Message.signout();

identify() fields

The identify payload accepts a fixed set of reserved keys plus any number of custom attributes. Reserved keys are typed; custom attributes are stored verbatim. Reserved keys:

  • email, used as the primary lookup. If a visitor with this email exists, the records merge.
  • name, display name shown in the inbox.
  • userId, your internal stable identifier. Use this if email can change.
  • userHash, HMAC signature for production identity verification. See Identifying visitors.
  • createdAt, unix seconds. When you created the customer in your system.
  • phone, E.164 format. Lets agents call them back from the inbox.
  • locale, BCP 47 code. Overrides the widget locale for this session.

Event listeners

Subscribe to lifecycle events with Message.on(eventName, handler). Listeners receive a single event payload. The return value of on is an unsubscribe function. See Widget events for the full event list and payload shapes.

JavaScript
Message.on('open', () => console.log('opened'));
Message.on('close', () => console.log('closed'));
Message.on('ready', () => console.log('bundle loaded'));

Message.on('message:received', (msg) => {
  console.log('agent reply:', msg.body);
});

Message.on('message:sent', (msg) => {
  console.log('visitor sent:', msg.body);
});

Message.on('conversation:started', (conv) => {
  console.log('new conversation:', conv.id);
});

Message.on('conversation:assigned', (conv) => {
  console.log('agent took over:', conv.assignedAgent.name);
});

// Remove a listener
const off = Message.on('open', handler);
off();

Headless mode

For fully custom launchers, set data-no-launcher="true" on the script tag. The bundle still mounts the chat panel inside Shadow DOM but does not render a launcher button. Open the panel from your own UI by calling Message.open().

HTML
<script src="https://app.message.com/widget.js"
  data-workspace="abc123"
  data-no-launcher="true"
></script>

<button onclick="Message.open()">Talk to support</button>

For deeper customisation (replacing the entire panel UI with your own React tree), see the planned React components SDK.

Server-pushed context

Anything you push through identify or update is visible to the agent in the inbox under Visitor details. It is also visible to message AI when grounding a response. Use this to surface CRM data, plan information, current page route, abandoned cart contents, or anything else that helps the agent help the customer.

For server-side syncs (your CRM pushing data into the workspace without a browser session), see Visitors API.

Common pitfalls

  • Identifying before signout. If you switch logged-in users without calling Message.signout() first, the new visitor inherits the previous conversation history. Always sign out on logout.
  • Identifying anonymously. Calling identify({}) with an empty payload throws. At least one of email, userId, or phone must be present.
  • Trusting the browser. Anyone can open dev tools and call Message.identify({ email: '[email protected]' }). For production, sign payloads with HMAC. See Identifying visitors.
  • Race with route changes. If you call update inside a router transition before the new route paints, the value sticks but the agent sees it before the visitor sees the page. Defer to the next tick if that matters.