Docs menu

Web widget

Identify users on the web widget

Sign your users in to the widget with an identity token from your backend.

To tell the Mentiora platform who is chatting, your backend mints an identity token and your page hands it to the widget. Without a token the visitor is anonymous.

Create an identity key

On the Install tab, create an identity key under Identity keys. Store the secret on your server, for example as MENTIORA_IDENTITY_SECRET. Never send it to the browser: anyone with it can sign in as any user.

The keys belong to the project, so every widget in the project accepts the same tokens. Up to two keys can be live at once, and tokens signed with either are accepted. To rotate, create a new key, deploy its secret, then retire the old key.

Mint a token on your server

The token is a JWT signed with HS256:

ClaimRequiredValue
subyesYour stable, non-guessable user id. Never an email.
audyes"mentiora"
iatyesIssue time. 60 seconds of clock skew is allowed.
expyesExpiry. You choose the lifetime.
any othernoCopied onto the user's profile in Mentiora.

Each token replaces the profile attributes the previous one set, so send every claim every time. Omitting a claim removes it.

A Node.js endpoint using jsonwebtoken:

JS
app.post("/me/mentiora-token", (req, res) => {
  const userId = req.session?.userId;
  if (!userId) return res.sendStatus(401);

  const token = jwt.sign(
    { sub: userId, plan: req.user.plan },
    process.env.MENTIORA_IDENTITY_SECRET,
    { algorithm: "HS256", audience: "mentiora", expiresIn: "15m" },
  );
  res.set("Cache-Control", "no-store").json({ token });
});

Protect this endpoint with your normal session check and CSRF protection. It issues credentials.

Register the token callback

Paste this block above the install snippet:

HTML
<script>
  window.mentiora = window.mentiora || function () {
    (window.mentiora.q = window.mentiora.q || []).push(arguments);
  };

  window.mentiora("identify", async () => {
    const res = await fetch("/me/mentiora-token", {
      method: "POST",
      redirect: "error",
      cache: "no-store",
      credentials: "same-origin",
    });
    if (res.status === 401) return null; // signed out
    if (!res.ok) throw new Error(`status ${res.status}`);
    return (await res.json()).token;
  });
</script>

The first two lines define a queue, so mentiora(...) calls made before the loader downloads run once it arrives.

Return null when nobody is signed in. Throw when you could not find out. A null returned for a server error signs the visitor out without any report.

The widget calls your function when it starts a session, before each session refresh, and once more after a rejected token. It does not start a session at page load, only when the visitor starts to engage, so the first call can come minutes later or never. Mint a fresh token on each call instead of returning one rendered into the page.

Sign-in and sign-out

  • On sign-in, call mentiora("identify", …) again. An anonymous conversation in progress becomes the user's and keeps its history.
  • On sign-out, call mentiora("logout"). This ends the session and deletes the stored token.

In a single-page app, wire both into your auth state changes.

Identity errors

To receive token failures, pass an object:

JS
mentiora("identify", {
  getToken: fetchMentioraToken, // your token function
  onError: ({ reason, message }) => {
    console.warn("Mentiora identity", reason, message);
  },
});
reasonWhen
token_rejectedThe token failed verification: bad signature, wrong aud, or a retired key.
token_expiredThe token's exp had passed.
callback_failedYour getToken threw or returned something that is not a token.
networkThe request to the Mentiora platform got no answer.
identity_requiredThe widget accepts only signed-in users.

onError is informational. The widget falls back to an anonymous session either way. Without onError, it logs one console warning per reason.

Signed-in users only

Only authorized users under Access on the Install tab stops anonymous visitors from starting a chat, on your website and in your apps. It needs an identity key.