Skip to main content

What it is

The web chat widget is just another channel in MINDO (like WhatsApp, Instagram or ManyChat): a chat bubble you embed on your site with a <script> that connects your visitors to your MINDO inbox. Whatever they write lands in the same Inbox where you already handle WhatsApp, and your team (or your AI agent) replies from there — the visitor gets the answer in real time, without reloading the page. It supports two kinds of visitor:
  • Anonymous — requires nothing from your backend. The widget generates its own visitor identifier (stored in the browser’s localStorage) so it recognizes the person between messages.
  • Identified — if the visitor is already logged in to your site, your backend can sign their identity so MINDO recognizes them. This merges, under a single contact, every chat that user opens from different devices, and keeps the conversation available when they come back.

Before you start

Make sure you have:
  • Access to Settings → Channels in MINDO with an administrator role.
  • Access to your site’s code (to paste a <script>).
  • If you’re going to identify logged-in users: access to your site’s backend, to sign the identity. The signature is always computed on the server, never in the browser.

Step by step

1

Create the Web channel

In MINDO, go to SettingsChannels and find the Web chat widget section. Click + Add Web channel.
Web channels section in MINDO

Web chat widget section in Settings → Channels

Fill in:
  • Session name — identifies the channel inside MINDO and is also the title the visitor sees in the chat header (for example, “Store chat”).
  • Primary color — the color of the panel header, the visitor’s bubbles and the Send button.
  • Welcome message — the first message the visitor sees while there’s no conversation yet. It isn’t stored as a message and doesn’t trigger the agent.
  • Agent (optional) — if you want an AI agent to reply automatically on this channel.
Form to create a Web channel

Web channel creation form

The agent won’t reply on the widget just because it exists in your company: it has to be assigned here. With No agent, messages wait for a human reply in the Inbox, like any other channel.
A company can have several Web channels at once —one per brand, per site or per country—. Each has its own token, color and agent, and conversations from one never mix with the other’s.
2

Copy the snippet

When you create the channel, MINDO shows you the snippet ready to copy:
You’ll also see an HMAC Secret — you only need it if you’re going to identify logged-in visitors (Step 4). Keep it somewhere safe; it must never be exposed in your site’s HTML.
Embed snippet and HMAC Secret of the channel

Snippet and HMAC Secret of the newly created channel

The snippet’s token is public: it travels in your site’s HTML and it’s expected to be visible. The Secret isn’t: it’s shown masked and only users with the ADMIN role of the company can see it (for a MEMBER or VIEWER the API returns the field empty).
3

Paste the snippet on your site

Paste the <script> right before the closing </body> on the pages where you want the chat to appear. No build step or dependency is needed — it’s a self-contained vanilla script.When the page loads you’ll see a chat bubble at the bottom right. Clicking it opens a panel with the chat (it’s an <iframe> to MINDO, so your site doesn’t need to implement any chat UI).
Widget panel open

Widget panel open over a sample site

If the bubble doesn’t show up, check the browser console: the most common error is an empty or wrong data-mindo-token.
The floating bubble is always blue. The primary color you configured applies inside the panel (header, visitor bubbles, Send button), not to the bubble. That’s the expected behavior, not a configuration error.
From here on, every visitor message creates a chat in your Inbox with channel Web, and your team handles it with the same composer as always. The widget chat adds one piece of data no other channel has: the “On the page” indicator, which tells you whether the visitor still has your site open right now.
Web chat in the MINDO Inbox with presence indicator

Widget chat in the Inbox, with the presence indicator

4

(Optional) Identify logged-in visitors

If your site has logged-in users and you want MINDO to recognize them (instead of treating them as anonymous), your backend signs a JWT and passes it in the data-mindo-identity attribute.The JWT is signed with the HS256 algorithm using the channel’s HMAC Secret, and its payload accepts these fields:
exp can’t be more than 7 days away. A JWT with a further expiration is considered invalid and the visitor stays anonymous. It’s a deliberate cap: if someone steals a token, seven days is the most that theft can be worth. A TTL of 24 to 72 hours is the usual choice.
Render the token into the <script> from a server-side template:
The HMAC Secret is a server-side secret. Never include it in HTML, client-side JavaScript, or a public repository — it should only exist in your backend, the same way you’d store any other API key.
With the identity signed, the chat stops showing “Visitor ####” and becomes the real person, with their phone and email already filled in on the contact record:
Widget chat with the identified contact in the Inbox

The same chat, now identified as the real contact

The signature is optional by design: if it’s missing, expired or invalid, the visitor simply stays anonymous — the chat is never blocked by a signature error. That means you can test without risking a broken widget.The flip side is that a malformed JWT fails silently. If the contact still shows up as “Visitor ####”, check in this order: that the secret belongs to the same channel as the token, that exp is in seconds (not milliseconds) and less than 7 days away, that the claim is named sub, and that the algorithm is HS256.
Before the JWT, identity was passed with three separate attributes. It still works and you don’t need to migrate: if you set both schemes at once, the JWT wins, and if the JWT is broken it falls back to this one.
Why the JWT is the better choice if you’re starting now: this scheme signs the string userId:expires using : as a separator, so it can’t carry a name or an email without becoming ambiguous. The JWT signs the exact data and lets you send name, email and phone — which is what gives the contact a real name and merges it with their WhatsApp chat.
5

(Optional) Identify the visitor after they log in

If your site is an SPA, or the visitor opens the chat before logging in, there’s no need to reload the page for MINDO to recognize them. The widget exposes a window.Mindo object:
The script loads with async, so window.Mindo may not exist yet when your code runs. That’s what the command queue is for: queue the calls and the widget processes them once it finishes loading.
You can also do it without writing any integration code: if your page stores the JWT in localStorage under the key mindo_identity, the widget picks it up on its own. This covers logging in from a new tab or through an OAuth redirect, because the widget listens for changes to that key. The same value can be broadcast over a BroadcastChannel named mindo-identity.
Besides setUser and clearUser, window.Mindo exposes open(), close() and toggle() to control the panel from your own UI (for example, a “Need help?” button), and on(event, callback) / off(event, callback) to listen for open, close, unread, identity, identity:cleared, auth:login and auth:register.
6

(Optional) Invite visitors to log in from the chat

The widget can show the anonymous visitor a block with Log in and Sign up buttons pointing to your site’s pages. It disappears on its own once the visitor is identified.
Widget with log in and sign up buttons

Login and sign-up buttons inside the widget panel

You configure it in Settings → Channels → Web chat widget, editing the channel: turn on Login buttons and fill in the URLs, the button labels and the message above them.
Configuration of the widget's login and sign-up buttons

Login buttons section when editing the channel

One of the two URLs is enough: the button without a URL isn’t rendered.You can also do it through the API, with an ADMIN user of the company:
On click, the widget opens the URL in a new tab. If you’d rather handle navigation yourself (for example, opening your own login modal), intercept it: returning false from the handler cancels the opening.
URLs must be https://. An http:// one is rejected on save, and if it was loaded by hand from the admin the button simply isn’t rendered.
Send the block in the auth field, not inside config. An explicit config replaces the stored one (except for prechat and auth), so a {"config": {"auth": {...}}} wipes your color and welcome message. The flat auth field is saved on its own, without touching anything else.

What happens next?

  • Every message a visitor sends creates (or continues) a chat in your MINDO Inbox, with Channel: Web.
  • If you identified the visitor and that same person writes from another device with the same sub, MINDO merges the history under a single contact.
  • If the JWT includes phone and that number already exists as a WhatsApp contact, MINDO merges them: you get one contact with both conversations (the widget one and the WhatsApp one) instead of two different people.
  • If you have an AI agent assigned to the channel, it can reply automatically; if not, the chat waits for a human reply like any other channel.

Frequently asked questions

No. The <script> is self-contained: it creates its own bubble and its own chat panel (an iframe). It requires no CSS, dependencies or build step.
Yes, paste the same snippet on every page where you want it to appear. The visitor is identified by an ID stored in their browser, so navigating between your pages keeps the same conversation.
Nothing is lost: the widget restores the conversation automatically on reload and shows it as soon as they open the panel, without them having to type again.
As long as they still have your page open, yes: the bubble shows a counter with the messages that arrived while the panel was closed, and it clears when they open it.
Widget bubble with the unread counter

Unread counter over the bubble

If they closed the tab, there’s no notice today: next time they come back to your site they’ll find the reply when they open the chat, but no notification reaches them meanwhile. That’s why it’s worth asking for a phone or email through the JWT (phone / email): with that data you can pick the conversation back up on another channel.
No. The widget composer is text only, with a cap of 4,000 characters per message. On the operator’s side files can be sent, and the visitor receives them in the panel.
Yes, anti-abuse caps per IP, well above what a real person does: 30 per minute to send messages, 20 per minute for the unread count and 10 per minute to open a session with a signed identity.
Nothing breaks: every visitor stays anonymous, each with their own chat. You can add identification later without changing anything you already installed.
No. The previous scheme is still supported and has no sunset date. Migrate only if you want to send the user’s name, email or phone — things the old format doesn’t support.
Yes. The channel has an allowed origins list (allowed_origins): with an empty list —the default— there’s no restriction; with origins configured, the page’s Origin header has to match one exactly or the API responds 403.It isn’t exposed in the Settings form yet: you set it through the API (PATCH /web-widget/channels/<id>/ with allowed_origins) or from the admin. If you turn it on, include every domain and subdomain your site is served from: a missing one leaves the chat broken on those pages.
Don’t turn it on today. The configuration exists in the backend (config.prechat, with off / optional / required levels for phone and email) but the widget doesn’t render that form yet, so it never sends that data.
With phone or email set to required, a new visitor’s first message gets 422 {"error": "Faltan campos obligatorios"} and the visitor can’t start the conversation. Leave it at off until the UI exists.
The Web channel has no messaging cost like WhatsApp (it doesn’t depend on Meta). Check with your MINDO plan whether any usage limit applies.