Skip to content

Embed the MyCLM assistant

The MyCLM assistant answers your visitors on your own website, with the AI agents and knowledge bases of your organization. No backend is needed on your side: the @myclm/chat SDK shows the assistant in an iframe served by MyCLM, and your visitors always talk to the MyCLM orchestrator, which picks the most suitable agent for each message and cites its sources.

  1. Create the integration in MyCLM. An organization administrator opens Administer <Organization> → AI integrations → New integration (in French: Intégrations IA → Nouvelle intégration) and sets:

    • the enabled agents (the pool the orchestrator picks from) and the organization knowledge bases usable for public answers (besides those provided with the agents; no other private data is ever used);
    • the users of the chatbot: anonymous visitors, or identified users (see Identified mode);
    • the allowed sites (Sites autorisés), one per line: paste any address, its host is kept (https://www.example.com/contact → www.example.com); *.example.com includes the subdomains;
    • an optional monthly message cap, on top of the AI message quota of the organization.

    Two publishable keys come with the integration (Publishable keys): pk_test_… and pk_live_…. They are not secrets: they identify the integration, and can be regenerated (the previous key stops working at once).

  2. Install the SDK.

    Terminal window
    npm install @myclm/chat

    No dependency, about 2 kB gzipped, ESM with TypeScript types.

  3. Mount the assistant in an element of your page. The iframe fills it: you decide its size and place (side panel, floating bubble, dedicated page).

    <div id="assistant" style="width: 400px; height: 600px"></div>
    import { MyCLMChat } from '@myclm/chat';
    const chat = MyCLMChat.mount('#assistant', {
    publishableKey: 'pk_test_…',
    locale: 'en',
    });

Embed code (Code d’intégration) in the integration page gives the snippet with your key.

Use the pk_test_… key while you build: it works on localhost and 127.0.0.1 (any port) in addition to the allowed sites. The pk_live_… key works only on the allowed sites, over HTTPS, never on localhost. A new integration without allowed sites therefore works nowhere in live mode, only in test.

Option Type Description
publishableKey string pk_live_… or pk_test_… key of the integration. Required.
locale 'fr' | 'en' Language of the assistant. Default fr.
theme 'light' | 'dark' | 'auto' Colour scheme. Default auto (the visitor’s system preference, followed live).
context object Context of the current page, see Page context.
user { idToken?, getIdToken? } Identified mode only, see Identified mode.
startClosed boolean Mount the assistant hidden; open() shows it.
apiBaseUrl string MyCLM API serving the assistant. Default: production. Only for an environment given by MyCLM.

mount returns an instance:

Method Description
setContext(context) Replaces the page context (sent after a short debounce, the last call wins).
open() / close() Shows or hides the iframe. The close button of the assistant calls close().
on(event, callback) Subscribes to an event; returns the unsubscribe function.
destroy() Removes the iframe and every listener.
Event Payload When
ready {} The assistant is loaded and initialized.
open / close {} The assistant was shown / hidden (by your code or its close button).
message { role, messageId, conversationId } A visitor message was stored (user) or an answer completed (assistant). The text is never exposed to your page.
error { code } See the codes below.
chat.on('message', ({ role, conversationId }) => analytics.track('assistant_message', { role, conversationId }));
chat.on('error', ({ code }) => {
if (code === 'site_not_allowed') console.warn('Add this site to the allowed sites of the integration');
});
Code Meaning
site_not_allowed The page is not on an allowed site of the integration (or not on localhost with a test key).
invalid_publishable_key Unknown or regenerated key.
identity_required, invalid_id_token, id_token_unavailable Identified mode: no ID token, a token refused by MyCLM, or getIdToken failed.
context_too_large, invalid_context The page context was refused (too large, not a plain object).
load_timeout The assistant did not load within 20 seconds.
quota_exceeded, integration_cap_reached, rate_limited, ai_timeout A message could not be answered (quota of the organization, cap of the integration, too many messages, slow answer).

Give the assistant what the visitor is looking at, as plain JSON (at most 4,000 characters once serialized, keys of 64 characters at most):

chat.setContext({ page: 'product', product: { name: 'Pro plan', price: '49 €' } });

The context is data for the assistant, never instructions: it is cleaned by MyCLM and given to the orchestrator in a delimited block. Do not put secrets or personal data you would not show the visitor.

By default visitors are anonymous: their conversations are kept 24 hours, for this browser only. In identified mode your signed-in users find their conversations on every device. Your users stay yours: they never become MyCLM accounts.

  1. In the integration, choose Identified users and set the issuer (iss, an HTTPS URL), the audience (aud) of your ID tokens and, when the keys are not published at <issuer>/.well-known/openid-configuration, the JWKS URL.

  2. Give the SDK the ID token (JWT) of the signed-in user, ideally through a function that returns a fresh one:

    MyCLMChat.mount('#assistant', {
    publishableKey: 'pk_live_…',
    user: { getIdToken: () => auth.getIdToken() },
    });

MyCLM verifies the signature against your JWKS (asymmetric algorithms only, keys cached), the iss, aud, exp and nbf claims (60 seconds of tolerance), then keeps only a hash of sub. When a token expires during the visit, the assistant asks your page for a new one (getIdToken is called again).

The allowed sites are enforced twice:

  • by the browser: the assistant page is served with a Content-Security-Policy: frame-ancestors listing your allowed sites only, so the iframe does not render anywhere else;
  • by MyCLM when the assistant opens its session: the origin of the parent page is checked against the same list.

On another site the assistant shows « Ce chatbot n’est pas encore autorisé sur ce site », the browser console names the detected host and the key, and the SDK emits error with site_not_allowed.

Each refused site is recorded in Blocked attempts (Tentatives bloquées) of the integration (host, number of attempts, first and last seen; kept 30 days). Only real browser loads are recorded, and the host is the origin declared by the browser, not verified. Allow asks you to confirm the exact host, then adds it to the allowed sites.

Wildcards (*.example.com) are refused when the base is a public suffix (*.github.io, *.vercel.app, *.co.uk, *.azurewebsites.net): the base must be a domain you own, such as *.myapp.com.

  • The iframe runs on the MyCLM origin with sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox": it reaches neither your DOM, nor your cookies, nor your storage, and your page cannot read the conversation.
  • The SDK and the iframe exchange postMessage messages only with each other’s origin, validate them against a strict schema, and ignore anything else.
  • The iframe is loaded with referrerpolicy="origin": MyCLM learns the origin of your page, never its path.
  • Sessions of the assistant are short (15 minutes, renewed automatically), bound to the integration and to the visitor or user; a conversation is only reachable by its owner. Anonymous visitors are recognized by a signed token kept in the iframe’s own storage; it cannot be forged or guessed from your page. Rate limits apply per visitor, per conversation, per integration and per IP address.
  • Public conversations only use the agents and knowledge bases of the integration, never other data of your organization, and never act on behalf of a user.
import { MyCLMChat } from '@myclm/chat/react';
export function Assistant({ open, onClose }: { open: boolean; onClose: () => void }) {
return <MyCLMChat publishableKey="pk_test_…" locale="en" open={open} onClose={onClose} context={{ page: 'pricing' }} style={{ height: 600 }} />;
}

react is an optional peer dependency, only needed for @myclm/chat/react.