Skip to content

Configure the widget from your page

The window.__m24 object the widget reads, covering visitor identity, page context for the AI agent and custom product card renderers.

Markdownllms.txt

The widget is configured by the script tag and by a global window.__m24 object that your page defines. It does not expose methods or emit events: there is no JavaScript call to open, close or reset the chat. Appearance, the welcome message and the visitor details form are set in the channel’s settings in Message24, not from your page.

Setting Type Read when
data-channel-key (script attribute) string Once, when the script runs. Required.
window.__m24.visitor { name?: string, phone?: string } When the widget loads and when it creates the visitor’s session.
window.__m24.pageData JSON object Every time the visitor sends a message.
window.__m24.renderers.product (product) => HTMLElement Every time a product card renders.
window.__m24.renderers.productList (products) => HTMLElement Every time a message with product cards renders.

Always extend the object rather than replacing it, so separate scripts do not overwrite each other:

window.__m24 = window.__m24 || {};

If your site knows who the visitor is, pass their name and phone so the conversation in the inbox is labelled with them instead of “Visitor”:

<script>
window.__m24 = window.__m24 || {};
window.__m24.visitor = {
name: "Alice",
phone: "+964 750 000 0000"
};
</script>
<script src="https://message24.net/widget.js" data-channel-key="YOUR_CHANNEL_KEY" async></script>

How it is used:

  • Set it before the widget script loads. The widget reads it once while starting up.
  • It is captured when the visitor first opens the chat in that browser, which is when the session is created. The name and phone are applied to the contact when the first message is sent. Changing window.__m24.visitor afterwards does not update an existing conversation.
  • If the channel has a visitor details form, the form is still shown, pre-filled with these values, and the visitor confirms or edits them.
  • Limits: name up to 120 characters, phone up to 40. The phone number is normalized by Message24; one that cannot be read as a phone number makes session creation fail with 400.

Without visitor and without a visitor details form, the conversation appears as “Visitor”.

Tell the AI agent and the team what the visitor is looking at. Set window.__m24.pageData to any JSON object:

<script>
window.__m24 = window.__m24 || {};
window.__m24.pageData = {
pageType: "product",
productId: "sku_123",
name: "Blue Sneakers",
category: "Shoes",
price: 79.99,
currency: "USD",
inStock: true
};
</script>

With each message, the widget sends a page context made of:

Field Value
url location.pathname at send time. Maximum 2,048 characters.
title document.title at send time. Maximum 300 characters.
data window.__m24.pageData at send time, if set. Must be valid JSON, 8 KB at most.

The page context is stored on the message and as the conversation’s current page.

The AI agent gets a one-line summary of the current page built from these keys in data, plus url:

Summary item Keys read from data, first one present wins
Page name, productName, title, product_title, then the page title
Price price or amount, with currency or currencyCode
Stock inStock or available (boolean)
Category category
Type pageType or type

Other keys, such as productId above, are stored with the message but are not part of that summary.

In a single-page app, update pageData as the route changes. See Single-page apps and route changes.

When the AI agent sends products, the widget shows product cards: an image, the name, price, a stock badge, and a View link when the business has product links set up. You can render your own cards instead, for example to add an “Add to cart” button wired to your store.

Register a renderer on window.__m24.renderers. It receives a product object and must return an HTMLElement:

<script>
window.__m24 = window.__m24 || {};
window.__m24.renderers = {
// Replace individual product cards
product: function (product) {
// product = { name, price, currency, imageUrl, url, inStock, externalId }
var card = document.createElement("div");
card.style.cssText = "border:1px solid var(--m24-border);border-radius:12px;overflow:hidden;background:var(--m24-surface);";
if (product.imageUrl) {
var img = document.createElement("img");
img.src = product.imageUrl;
img.alt = product.name;
img.style.cssText = "width:100%;height:160px;object-fit:cover;display:block;";
card.appendChild(img);
}
var info = document.createElement("div");
info.style.padding = "12px";
var name = document.createElement("div");
name.textContent = product.name;
name.style.cssText = "font-weight:600;font-size:14px;color:var(--m24-text);";
info.appendChild(name);
var row = document.createElement("div");
row.style.cssText = "display:flex;align-items:center;justify-content:space-between;margin-top:8px;";
var price = document.createElement("div");
price.textContent = new Intl.NumberFormat(undefined, {
style: "currency", currency: product.currency || "USD",
minimumFractionDigits: 0, maximumFractionDigits: 2
}).format(product.price);
price.style.cssText = "font-weight:700;font-size:15px;color:var(--m24-text);";
row.appendChild(price);
var btn = document.createElement("button");
btn.textContent = "Add to Cart";
btn.style.cssText = "border:none;border-radius:8px;padding:6px 14px;font-size:13px;font-weight:600;cursor:pointer;background:var(--m24-accent);color:#fff;";
btn.addEventListener("click", function (e) {
e.preventDefault();
e.stopPropagation();
// Wire to your cart API here
btn.textContent = "Added!";
btn.disabled = true;
});
row.appendChild(btn);
info.appendChild(row);
card.appendChild(info);
return card;
},
// Or replace the entire product list container (optional)
// productList: function (products) {
// var grid = document.createElement("div");
// grid.style.cssText = "display:grid;grid-template-columns:1fr 1fr;gap:8px;";
// products.forEach(function (p) { ... });
// return grid;
// }
};
</script>

renderers.product replaces each card inside the widget’s own layout; a message with more than one product is shown as a horizontal carousel. renderers.productList receives all of a message’s products as an array and replaces the whole group, so you control the layout. If both are set, productList wins.

Field Type Description
name string Product name.
price number Selling price. For a product with variants, the lowest variant price.
currency string The business’s currency code, for example "IQD" or "USD".
imageUrl string, optional First product image. A signed, time-limited URL: display it, don’t store it.
url string, optional Link to the product on the business’s website. Present only when the business has set up product links.
inStock boolean Stock availability.
externalId string The product’s ID in the business’s own catalog, useful for calling your cart API.

Your elements render inside the widget’s Shadow DOM, so your site’s stylesheets do not apply to them. Use inline styles, and these variables to match the widget:

var(--m24-accent) /* Brand colour, from the channel's Primary Color */
var(--m24-text) /* Main text: #1a1a1a */
var(--m24-text-muted) /* Muted text: #8b8b8b */
var(--m24-surface) /* Background: #ffffff */
var(--m24-surface-alt) /* Alt background: #f4f5f7 */
var(--m24-border) /* Border: #e8e8e8 */

If a renderer throws, the widget logs [m24] Custom product renderer error to the console. If it returns something that is not an HTMLElement, it logs [m24] Custom product renderer must return an HTMLElement. In both cases the card area stays empty; the widget does not fall back to its default card, so test your renderer against real products.

  • Call e.stopPropagation() in button handlers inside a card so the click does not reach anything underneath.
  • Define window.__m24.renderers before the widget script loads, so the first cards already use it.
  • To render with React or Vue, create a container element, mount your component into it with createRoot or createApp, and return the container.
  • Try your renderer on the test page before deploying.

Replies can contain Markdown links ([text](url)) and bare http or https URLs, which the widget turns into links and link cards. A link to the same host as the page opens in the same tab; any other link opens in a new tab. javascript:, data:, vbscript: and file: links are shown as plain text.