The messenger on your profile pages
Visitors write to a profile from the messenger on your pages. You can add it in two ways:
- The loader, the default: a small script shows a launcher button in the corner of the page, and the messenger opens in a frame served by the platform. Your page's styles and scripts cannot reach the conversation.
- The
mp-messengerelement: the messenger runs on your page itself, inline in your layout or in the corner, in your colours and font. Your page's scripts can then read the conversation, so it is off until you switch it on for the site.
Either way, the messenger shows a profile only after your backend has sent it (guide 2). Your pages name a profile by the same external_id your profile sync uses. A profile the platform does not have shows as not available.
The loader
The loader is one classic script at the platform's widget address, {appUrl}/loader.js, which defines MessengerWidget (Adding the loader). Load it with defer, and call it from your own deferred script listed after it:
<script src="https://chat.example/loader.js" defer></script>
<script src="/js/messenger.js" defer></script>
<!-- On Lena's profile page -->
<button type="button" data-messenger-profile="example-lena">Message</button>
// /js/messenger.js
const widget = MessengerWidget.createWidget({
appUrl: "https://chat.example",
site: "pk_test_...",
});
// Each "Message" button with a data-messenger-profile attribute opens that profile's chat.
for (const button of document.querySelectorAll("[data-messenger-profile]")) {
const profileId = button.dataset.messengerProfile;
button.addEventListener("click", () => widget.open({ profileId }, button));
}
appUrlis the widget address of the platform you integrate with. The platform team gives it to you, and the Widget snippet card on the Integration page shows a script like this one, filled in with your addresses and key, ready to copy.siteis the site's publishable key (guide 1).- Set each button's
data-messenger-profileto the profile'sexternal_idfrom profile sync. A page without such a button is left as it is, and visitors there still have the launcher. widget.open({ profileId }, button)opens the panel on that profile's chat. Without a profile it opens the visitor's chats, as the launcher does. Focus goes back tobuttonwhen the panel closes.createWidgettakes more options:getUserTokento sign visitors in (guide 4),accentandaccentTextfor the launcher's colours,embed: "element"for the element in the corner, andonReady. The table in Adding the loader lists them all.
No inline script is needed, so a strict Content Security Policy only has to allow the widget address in script-src and frame-src.
The launcher shows how many replies the visitor has not read yet, once the visitor has opened the panel on that page (The launcher). The panel takes at most 380 by 560 pixels in the bottom right corner, and never moves your page's content.
What visitors see
A chat opens with the profile's card at the top of the panel:
- the first letter of the profile's public
name, with your site's two-letter mark on it; - the public
nameas the chat's heading; - under it, your site's name and the profile's public
headline.
The platform team gave your site its name and mark, and the console shows both, such as "SpaGuide (SG)". Without a public name, the heading reads "Chat" and the mark stands alone. Nothing else from the profile appears (guide 2, What each field feeds).
Above the messages of every chat, a notice reads "Lena's AI assistant may reply when the profile owner is away. Its messages are always labelled." Every AI reply carries the label "Lena's AI assistant". Both name the AI assistant after the profile's public assistant_name, or its public name when there is no assistant_name and the name fits the label's rule (The name in the AI label). With neither, the notice names no one: "An AI assistant may reply when the profile owner is away. Its messages are always labelled."
Elsewhere the messenger names the profile by its public name: in the visitor's list of chats, and in sentences about the owner, such as "Lena, yoga will reply here" in the chat and "Lena, yoga replied" when the owner answers in another chat.
Nothing on your page can remove or restyle the notice or the label: not your styles, and not the element's theme. Every message the platform returns also carries a machine-readable AI flag.
Guests and signed-in visitors
A visitor who is not signed in on your site writes as a guest, without registering. A guest's chats last one browser session on your site.
A visitor signed in on your site is recognised without a second sign-up, and keeps their chats across browsers and devices. When a guest signs in, the chats they had as a guest on your site in that browser session move to their account. This needs a user token from your backend: guide 4 shows how.
The mp-messenger element
Choose the element when the messenger should sit inline in your profile page, use your colours and font, or keep its session on your own origin (contracts/widget-element.md).
Switch it on first. On the Sites page, a developer or an admin turns on "Messenger element on the pages of" your site. It then works only on pages at the site's allowed origins (guide 1). Switching it off later signs every visitor on the site out of the messenger.
Then load the module once from the widget address, and put the element where the chat should be (Loading):
<script type="module" src="https://chat.example/element.js"></script>
<mp-messenger site="pk_test_..." profile="example-lena" heading-level="2">
Messages could not load. <a href="/contact">Contact us</a> instead.
</mp-messenger>
- The content inside shows until the module has loaded, and stays when it cannot load, so put a short fallback there.
siteis the publishable key, read once when the element first connects.profileis the profile'sexternal_id; changing it opens that chat.heading-level, 2 to 6, fits the panel's heading into your page's outline (Attributes and properties).- Inline, the element fills its container's width and takes the height you give it, at least 360 pixels.
- For the element in the corner with the launcher, use the loader with
embed: "element"instead (Two ways to place it).
To sign visitors in, set getUserToken on the element, as in guide 4. To fit your design, set four custom properties: --mp-accent, --mp-accent-text, --mp-font and --mp-radius (Theming). The accent must reach a contrast of 3:1 against the panel, and its text 4.5:1 against the accent; otherwise the element keeps the platform's accent and warns in the console.
Your Content Security Policy must allow the widget address in script-src and font-src, and the platform's API address in connect-src.
Know the trade-off before you choose the element. On your own page, your scripts and any third-party script there can read what the element shows, including the visitor's session. That session reaches only this visitor's chats on your site. A guest's session works for 12 hours and renews itself; a signed-in visitor's works for one hour and renews only with a fresh user token from your backend (Security).
Checking it works
Open one of your profile pages in the sandbox and press its "Message" button. The panel opens on that profile's chat with its card. If it says the profile is not available, check that your backend sent the profile with the external_id your page uses: the partner console lists recently synced profiles on its Profiles page.
Next: signing visitors in, so a visitor signed in on your site is signed in to the messenger too.