MxChat Core
The free MxChat plugin — the AI chatbot itself, plus everything that powers it: setup, AI models, the knowledge base, behavior, actions, display, and the REST API. Add-ons extend this core; this page documents the core itself.
Overview
MxChat turns any WordPress site into an AI chatbot that answers from your content. It runs on your server, connects to the AI provider of your choice, and answers visitor questions using a knowledge base you control — no per-message fees, no data leaving your stack except the calls you make to your chosen AI provider.
Core capabilities:
- Bring-your-own AI — OpenAI, Anthropic Claude, Google Gemini, xAI Grok, DeepSeek, or any OpenAI-compatible endpoint (Ollama, LM Studio, vLLM, Azure OpenAI).
- RAG knowledge base — index your pages, posts, PDFs, and custom text so the bot answers from your real content.
- A guided setup wizard that walks you from "just installed" to "live on my site."
- Actions — let the bot do things (capture emails, search the web, generate images, hand off to a human) not just answer.
- A REST API for headless access to transcripts and knowledge.
Getting Started
When you first open MxChat in your WordPress admin, you land on the Onboarding wizard. It walks you through setup one step at a time:
- Chat model — pick your AI provider and model, and paste your API key inline.
- Behavior — tell the chatbot how to act (its role, tone, and the topics it should stick to). Optional — you can use the AI's defaults and refine later.
- Embedding model — pick the model used to index your knowledge base. If it's the same provider as your chat model, your key is reused automatically.
- Knowledge base — optionally add your first content so the bot has something to answer from. You can skip this and build it later.
- Actions — optionally enable Actions (see below). Skippable.
- You're set up — test the bot in your dashboard, turn it on for your site, or grab an embed shortcode.
You can reopen the setup guide any time from Settings → Tutorials.
AI Models & Providers
Choose your chat model under Settings → AI Models → Select AI Model. MxChat supports:
- OpenAI — the GPT-5 family (including GPT-5.6 Sol, GPT-5.5, and GPT-5.4).
- Anthropic Claude — the Opus, Sonnet, and Haiku families, including Claude Fable 5, Claude Opus 5 (added in 3.2.15, priced the same as Opus 4.8), and Claude Opus 4.8.
- Google Gemini — the Gemini 3.x lineup: Gemini 3.8 Flash (the recommended Gemini default from 3.2.22), 3.7, 3.6 and 3.5 Flash, 3.1 Pro, and the Flash-Lite models (3.5 Flash-Lite is the lowest-cost choice), plus Gemini 2.5. Sites already on 3.5 Flash keep it until they pick something else.
- xAI Grok — the current Grok generation, led by Grok 4.6 (refreshed in 3.2.19; existing selections keep working).
- DeepSeek — DeepSeek V4 Flash and DeepSeek V4 Pro.
- Custom (OpenAI-compatible) endpoints for local or self-hosted models.
DeepSeek users: DeepSeek retired its older API model names on July 24, 2026, which broke chat on every site still pointing at one of them. Core 3.2.15 replaced them with V4 Flash and V4 Pro, and a site still set to a retired DeepSeek model is moved to V4 Flash automatically when it updates — so the fix is simply to update to 3.2.15 or later. If DeepSeek chat is failing on an older version, that's the cause.
OpenAI GPT-5.1 Chat Latest and GPT-5.3 Chat users: OpenAI retires both models on August 10, 2026. Core 3.2.16 removes them from the picker, and a site still set to either one switches to GPT-5.6 Sol automatically, with an admin notice explaining the change. Same shape as the DeepSeek migration above — updating is the fix.
The daily model-liveness check (3.2.19)
Retirement dates only help for retirements a provider announced in advance. From 3.2.19 MxChat also checks once a day that the model you have selected still exists, and warns you on the AI Models screen and the dashboard before a retired model can silence your chatbot. Sites still set to the retired Claude Opus 4.1, or to older retired Claude models, are moved to the current Claude generation of the same tier automatically and shown a notice.
Claude prompt caching (3.2.19)
Claude API costs drop on most sites from 3.2.19 — MxChat now uses Anthropic's prompt caching automatically, with nothing to configure. This landed ahead of Anthropic's 1 September Claude Sonnet 5 price change, so the saving offsets part of that increase for sites on Sonnet.
Gemini thinking level (3.2.22)
Gemini 3-series models reason before they answer, and that hidden reasoning is billed as output tokens. From 3.2.22 MxChat asks those models for a low thinking level on every chat reply — natively and through the OpenAI-compatible provider — so a chatbot answering from a knowledge base stops paying for deliberation it does not need. Flash-Lite models do not think and are left alone. A developer can change it with the mxchat_gemini_thinking_level filter.
Retirement dates in the model picker (3.2.16)
Providers retire models on published dates, and up to now that only became visible when chat broke. Since 3.2.16 the model picker shows the date on any model with an announced retirement — the entry reads "<model name> — retires <date>" — and the model disappears from the list once that date passes, so you can't newly select something that is already gone. A model you have already selected stays visible in Settings even after retirement, marked as retired, so the screen never silently shows you a different model than the one that is actually saved.
Add your API key for each provider you use under Settings → API Keys. MxChat detects a saved key and confirms it inline. You can switch models at any time; the model you pick is the one used for live chat answers.
The model list refreshes as providers ship new models. If a provider retires a model you had selected, MxChat automatically falls back to a current, working model on your next admin load — you're never stranded on a dead model.
If your provider starts rejecting the model (3.2.16). When a provider replies that the selected model isn't available on your key — "does not exist", "you do not have access", "permission denied", and the equivalent wording from Anthropic, OpenAI, xAI and Gemini — MxChat now raises a persistent admin notice naming the model and linking to Settings. Before 3.2.16 only the visitor in the chat window saw anything, so a bot could sit broken for days while the owner heard nothing. The notice is throttled to once an hour per model, so a busy broken bot doesn't flood the dashboard.
Custom & Azure OpenAI endpoints. Point MxChat at any OpenAI-compatible endpoint — Ollama, LM Studio, vLLM, llama.cpp, or Azure OpenAI — under Settings → API Keys → Custom Provider. Set the Base URL, API key, and auth scheme (Azure also takes an API version), then use the one-click Test Connection button to confirm it works; a built-in Azure OpenAI quick-start lists the exact values to paste. You can also route your knowledge-base embeddings through the same endpoint by enabling "use custom provider for embeddings" — indexing and live queries then use your endpoint's embedding model.
Local-only embedding setups (fixed in 3.2.17). If you run embeddings entirely through a custom provider and have no cloud key saved at all, ingestion now works end to end. Before 3.2.17 the import screens and the automatic post-sync checked for an OpenAI, Voyage or Gemini key before handing the job to the embedding layer — so a pure Ollama or LM Studio site got misleading "API key missing" errors on import, automatic indexing of saved posts silently did nothing, and a permanent model-mismatch banner sat on the Knowledge screen. All of those pre-flight checks are now aware of the custom provider, and the banner is gone.
Each provider's API key field now has a one-click Test key button (added in 3.2.11) that runs a quick, free validation so you can confirm a key works the moment you paste it, rather than finding out only when a chat fails.
Built-in Web Search. Turn on Settings → AI Models → Enable Web Search to let the chatbot ground its answers in live web results when a question needs current information. It uses the model provider's own search tool: OpenAI models search through OpenAI's built-in web search, and Google Gemini models now do the same through Google Search grounding (added in core 3.2.11 — previously this toggle only affected OpenAI and was a silent no-op for Gemini, so Gemini sites had to add the Perplexity add-on for web-grounded answers). Either way it uses the API key you already configured for that model, at no extra cost. This is separate from the Brave Web Search Action and the Perplexity add-on, which are other ways to add web search under Actions.
The Knowledge Base (RAG)
The knowledge base is what makes your chatbot know your stuff. Under Settings → Knowledge you can:
- Auto-sync your posts and pages so published content is indexed automatically. From 3.2.17 a scheduled post is indexed at the moment it actually goes live, rather than being missed because it was published by the scheduler instead of by a person.
- Upload PDFs and Word documents to extract and index their text — one at a time under Import Options, or in bulk from 3.2.22: choose WordPress Content with the content type set to Media and the importer lists the PDF, Word, text and Markdown files already in your Media Library (the types it can read text from; images, audio and video are not shown), so you can select a page of them and import them together. Switch on Media under Auto-Sync Settings → Advanced Custom Post Sync Settings and a supported file adds itself to the knowledge base on upload, updates its entry when replaced, and is removed when deleted. (Before 3.2.22, choosing Media listed nothing on every site.)
- Add manual entries — paste any text you want the bot to know.
- Index content from a sitemap.
By default MxChat stores embeddings in your WordPress database. For larger knowledge bases you can switch to Pinecone or OpenAI Vector Store under the Knowledge page.
If you use OpenAI Vector Store, update to 3.2.18. On earlier versions every Vector Store search failed against OpenAI's API and the failure was swallowed, so the chatbot answered with no knowledge base at all — confidently, and with no error anywhere for you to notice. Nothing about your vector store or your key was wrong, and there is nothing to re-index: updating restores retrieval on the next question. The same release also fixes the Knowledge status readout, which reported "no vector stores configured" even when they were.
If you ever change your embedding model — including enabling a custom provider for embeddings — re-index your whole knowledge base (Knowledge → Process Selected) so your stored vectors and your query vectors come from the same model. A model mismatch between indexing and querying is the most common reason the bot seems to "ignore" content you've added.
Tune retrieval under Settings → Behavior: the Similarity Threshold controls how strict content matching is, and the RAG Sources / Chunks limits control how much context is sent to the AI per answer.
Pinecone document index with full-text search (3.2.22)
Pinecone offers two kinds of index and MxChat supports both. A vector index — the default, and what every existing setup uses — stores your embeddings and answers similarity queries. A document index with full-text search additionally keeps a keyword index of the stored text, so a question that contains a part number, SKU or code is matched on the literal string as well as on meaning. Choose the type under Knowledge → Pinecone → Index type; the classic vector path is untouched, so nothing changes for a site that leaves the default.
A document index is a separate index at Pinecone. Create it with Create index for me — a new index named after your Index Name field, sized for your embedding model, in the cloud, region and language you pick, with the host filled in for you — or enter an existing document index's host and click Check index, which refuses a classic index, a foreign schema or a dimension mismatch with the exact reason. The type only saves once the host has been checked. Migrate then copies your existing vector index into the document index — text, vectors and metadata, same ids — with no re-embedding; it runs in resumable batches and is safe to run again. Delete old index appears once the copy count matches and asks you to type the index name. Your embedding provider and model do not change.
With the index type on Document index, switch on Hybrid keyword boost under Chunking & Retrieval: a question carrying a code-like token gets a second lookup restricted to records containing that code (with a full-text search as the fallback), fused with the semantic results, and the Testing and Transcripts panels label each match Vector, Keyword or Both. The Multi-Bot add-on does not yet offer a per-bot index type.
Also fixed in 3.2.22: with Pinecone, the Knowledge Entries heading now shows the vector count Pinecone reports instead of "(50)" for any index over 500 vectors, paging uses Previous and Next and continues where the last page ended, and a bot with its own empty namespace shows 0.
Role restrictions: any role, and pages too (3.2.22)
Knowledge → Role Restrictions maps a post tag to the role a visitor must hold for the chatbot to retrieve that content. From 3.2.22 the role list is built from the roles your site actually has, so alongside Public, Logged In Users and the built-in Subscribers & Above through Administrators Only you can pick a custom role from User Role Editor, Members or a membership plugin; access is granted to that role or to any role whose capabilities cover it, which keeps the built-in "& Above" ladder exactly as it was. Because tags only exist on posts, every post and page also gets a Knowledge base access dropdown in the MxChat box on its edit screen (default Use tag rules), so a page or an untagged post is no longer stuck as public; where both apply, the stricter of the tag rule and the page setting wins. The same dropdown sits on each entry in the Knowledge list for content that came from a PDF, a URL or an upload. This release also closes a leak: on earlier versions a restriction set to a custom role was readable by every signed-in visitor.
Hybrid keyword boost (3.2.16)
Vector search matches on meaning, which is exactly wrong for a question built around an exact token — a product code, a SKU, an error code, a person's name. Semantically, ERR-4102 looks a lot like ERR-4103.
Knowledge → Chunking & Retrieval → Hybrid keyword boost (labelled WordPress database and Pinecone document indexes from 3.2.22) combines keyword matching with the existing similarity search so those questions find the right document. It is off by default. (In 3.2.17 this setting moved here from Settings → Behavior, alongside the chunking controls it belongs with; your saved choice carried over, and the old location links to the new one.) Two things to know before enabling it:
- It affects the WordPress-database knowledge base and, from 3.2.22, a Pinecone document index (see above). On a classic Pinecone vector index or an OpenAI Vector Store the toggle does nothing.
- It changes which sources are retrieved on an existing install. Ask your bot a handful of your real questions after turning it on rather than assuming it is a free win.
While it is on, the Transcripts and (from 3.2.22) Testing panels label how each match was found — Vector, Keyword, or Both — so you can see whether the keyword half is actually rescuing anything before you leave it on.
Unpublished content and the knowledge base (3.2.16)
Unpublishing, trashing, or making a post private now always removes it from the knowledge base — including status changes made by scheduled-expiry plugins that change post status directly and never touch the edit screen. Previously those could leave a chatbot answering from content that is no longer public on the site.
To clear entries left behind by earlier unpublishes, run the new WP-CLI command once:
wp mxchat prune-unpublished --dry-run
wp mxchat prune-unpublished
The --dry-run pass reports what it would remove without deleting anything.
Behavior & System Instructions
Under Settings → Behavior, the AI Instructions field is the chatbot's "job description" — the instructions it follows on every reply (its role, tone, and guardrails). This is the highest-leverage setting for making the bot sound like your brand.
Since 3.2.15 you can also decide where your knowledge-base content is inserted into those instructions, using the context placeholder — put it wherever the retrieved content should sit, so you can write rules that come after the source material. Leave the placeholder out and MxChat behaves exactly as before.
Since 3.2.16, when the knowledge base has nothing relevant to a question, the chatbot is told that plainly instead of being handed a "no information found" note formatted like knowledge base content. Previously the model could treat that note as source material and answer around it; now it simply says it doesn't know. If your bot used to produce oddly confident non-answers on out-of-scope questions, this is the change.
The chatbot knows what day it is (3.2.22). Every request now carries a line of the form Current date and time: Monday, September 21, 2026, 9:15 AM (Europe/Amsterdam). Anything dated before today is in the past., built from the timezone under Settings → General, so the model can tell a past event from an upcoming one without a rule from you. The line travels with the per-message context rather than inside the instructions, so it does not affect prompt caching. If you want the date at a particular spot in your own rules, {current_date} and {current_datetime} are replaced in the AI Instructions field — with the caveat the field's hint spells out: a placeholder changes the instructions once a day or once a minute and reduces how much of the prompt your provider can cache, so most sites do not need one. Developers can reword or suppress the automatic line with the mxchat_current_datetime_line filter.
Note that Actions dispatch outside the reply text, so an instruction like "never ask visitors for their email" will not reliably stop an enabled Action from firing. To stop an Action, disable it under Settings → Actions — see the FAQ entry on the mailing-list prompt.
Other behavior controls:
- Contextual Awareness — let the bot reference the current page's content for more relevant answers. From 3.2.22 the page text is read from an inert copy gathered once per page: on earlier versions the copy was made live on every message, and on a page with a video or audio player it could start an invisible copy playing (with sound, if the visible player had been unmuted) and download the media again each time.
- Citation Links — allow the bot to include source links from your knowledge base.
- Strip Unapproved Links (3.2.20+) — remove links the AI invents, even when Citation Links is off. MxChat has always checked every URL in a reply against an approved list and dropped the rest, but until 3.2.20 that enforcement rode on Citation Links, so switching citations off also switched the guard off and let fabricated URLs through. It is now its own control. Approved citations, real pages on this site, and links returned by your integrations — WooCommerce product URLs, for example — are always kept. On by default for new installs; existing sites keep their current behaviour until you turn it on.
- Satisfaction Rating — show a 👍 / 👎 prompt after a conversation so you can measure answer quality.
- Message limits — cap how many messages visitors can send per hour, day, week, or month. Set a limit per user role (including logged-out visitors), or a single total cap across everyone, each with a live usage readout ("10 of 200 used · 190 left · resets in ~6 hours") and a one-click reset. Limits accept any whole number, not just the presets; the default is Unlimited, so existing sites are unchanged until you set one. From 3.2.22 a visitor's allowance is counted against the address the request really came from — Cloudflare is recognised automatically, and other proxies can supply the address with the
mxchat_client_ipfilter — and daily, weekly and monthly limits hold for the full period. On 3.2.21 and earlier the per-visitor key came from a client-supplied header and every counter was cleared hourly, so a daily cap effectively reset each hour; if your limits never seemed to bite, that is why. - Markdown in the chat window — replies (and the visitor's own messages) are formatted for bold, italic, strikethrough, headings, code and tables. From 3.2.22 words joined with underscores — file names, SKUs,
snake_caseidentifiers,_PLACEHOLDER_tokens — keep their underscores instead of turning italic, a backslash writes an underscore, asterisk, tilde or backtick literally, and anything inside backticks is shown exactly as written. There is no switch to turn formatting off.
Actions
Actions let your chatbot do things, not just answer — capture an email, search the web, generate an image, answer from a PDF, or hand off to a human. The free core includes:
- Loops Email Capture — collect a visitor's email into your Loops mailing list.
- Brave Web Search and Brave Image Search — search the web and images from chat.
- Generate Image — create an image with OpenAI (GPT Image) or Google (Imagen).
- Chat with PDF — answer questions about an uploaded PDF.
- Live Agent Handoff — transfer the conversation to a human on Slack or Telegram, and hand it back to the bot when done.
There are two ways the bot decides when to run one of these, both under Settings → Actions:
- AI Tools (function calling) — the model decides on its own when to use an enabled tool, straight from the visitor's natural-language message, with no trigger phrases to maintain. Enable individual tools under Actions → AI Tools. AI Tools is off by default, and every tool is turned on deliberately — sensitive ones (anything that spends money, exposes customer data, or hands off to a human) stay off until you switch them on. Each tool can take an optional hint that tells the model when to reach for it; from 3.2.19 the two live-agent handoff tools arrive with that hint prefilled, so automatic escalation works as soon as you enable them, and you can reword or clear it. AI Tools needs a tool-capable chat model; if your current model can't call tools, the page says so and the tools simply won't fire until you pick one that can. From 3.2.22 a question that needs no tool is generated once instead of twice, so ordinary turns arrive sooner and use roughly half the output tokens; those replies arrive as one message, and the
mxchat_fc_keep_first_hop_textfilter restores the old two-part behaviour. The same release fixes the loop sending an invalid request once the per-turn tool budget was spent — every tool call now gets a result, the model answers from what it has, and a provider failure after a tool has run is logged even with developer mode off.
Seeing which tools ran (3.2.19)
Until 3.2.19 the Message Context panel in Transcripts reported only how Trigger Phrases scored, so a site running purely on AI Tools saw "No action analysis available for this message" while its tools were firing correctly. From 3.2.19 each message also records which AI Tools ran, how long each took, and the error text if one failed. Tools that handle money, customer records or a live-agent handoff record only the fact that they ran, never their arguments — the fired-fact is the half you need for debugging, and the arguments are the half that carries personal data. The record is written as the answer is generated and is never backfilled, so it does not appear on conversations from before you enabled the tool.
- Trigger Phrases — the original approach: you list the phrases that should fire an Action, and a matching message runs it. Found under Actions → Trigger Phrases (this is the renamed home of the phrase-matching system).
You can run both at once — when a visitor's message matches a trigger phrase that fires first, and AI Tools cover everything else. Many add-ons (WooCommerce, Forms, Perplexity, and more) register additional Actions, and those become available as AI Tools too.
Brave Web & Image Search
The web and image search Actions run on the Brave Search API. Brave operates its own independent web index rather than reselling another engine's results, which is why these are separate from the Enable Web Search toggle under AI Models (that one uses your model provider's built-in search) and from the Perplexity add-on. Both Brave Actions ship with the free core plugin, and both need a Brave Search API key before they will return anything.
Step 1 — Get a Brave Search API key
- Create an account at api-dashboard.search.brave.com.
- Subscribe to a Search API plan. Brave offers a free tier that is enough to try the feature out.
- Copy your subscription token.
Step 2 — Add the key in WordPress
Paste it into Settings → API Keys → Brave API Key and save. The Settings → Brave Search tab holds the search options described below, but the key itself lives on the API Keys tab alongside your model keys.
Step 3 — Turn the Actions on
Under Settings → Actions → AI Tools, in the Search Features group, enable:
- Brave Web Search — searches the web and answers from the results.
- Brave Image Search — returns images inline in the conversation.
AI Tools is off by default and every tool is enabled deliberately, so nothing searches until you switch it on. AI Tools also needs a tool-capable chat model. If you would rather match on wording than let the model decide, both Actions can be fired from Actions → Trigger Phrases instead.
If either Action is enabled while no Brave key is saved, the Actions page shows a warning — without the key the tool is registered but silently returns nothing.
Search options
Under Settings → Brave Search:
- Number of Images to Return — how many images an image search shows. Defaults to 4.
- Safe Search — filters adult content in image results: Strict (the default) or Off.
- Number of News Articles — how many news results to include.
- Country — biases results toward a country.
- Language — biases results toward a language.
Web search returns five results per query.
How a search actually runs
- The query is rewritten first. MxChat does not send the visitor's raw message to Brave. Your selected chat model interprets it into a focused search query, so "do you know anything about what happened with that new pricing thing" becomes something Brave can actually match. If the model cannot make a query out of the message, the bot asks the visitor to rephrase instead of searching blindly.
- Brave is called server-side —
api.search.brave.com/res/v1/web/searchfor web and/res/v1/images/searchfor images, authenticated with your subscription token in theX-Subscription-Tokenheader. The key never reaches the browser. - Results are cached. Each distinct query is stored in a WordPress transient, so repeated questions do not spend quota twice.
- The model answers from the results, with links, rather than pasting a raw result list.
Troubleshooting Brave search
- The bot never searches. Check that the Action is enabled under Actions → AI Tools, that a Brave API key is saved under API Keys, and that your chat model supports tool calling.
- Results look stale after changing settings. Searches are cached per query. Try a differently worded question, or wait for the cached copy to expire.
- Image results are missing or filtered. Safe Search defaults to Strict. Set it to Off under Settings → Brave Search if the topic legitimately needs it.
- Nothing returned for an obscure query. The rewritten query is what reaches Brave; check the Transcripts → Message Context panel to see which tools ran.
Slack Live Agent Handoff
The Live Agent Handoff Action lets a visitor escalate from the AI to a real person. Your team replies inside Slack and every reply is relayed straight back to the visitor's chat window — there's no separate agent dashboard to watch.
How it works: a visitor's message matches a trigger phrase, so MxChat opens the conversation in Slack, invites your agent User IDs, and posts a New Live Agent Request with the session ID and the last few messages of context. Agents reply there, and MxChat relays each reply back to the visitor through /wp-json/mxchat/v1/slack-messages. The session stays in live-agent mode until it's handed back to the AI.
Two channel modes (the shared-channel option was added in 3.2.15). By default MxChat creates a new public channel per conversation, named after the chat session. Since 3.2.15 you can instead point every handoff at one shared channel your team already monitors, with one thread per visitor — useful if per-visitor channels were cluttering your workspace. Set the shared channel in the Slack settings; leave the field blank and behavior is unchanged.
Where to reply (changed in 3.2.21). In a shared channel every conversation lives in a thread rooted at its handoff message, and agents must reply inside that thread — a channel-level reply there reaches nobody. In a per-conversation channel, agents can reply in the channel or in a thread under the handoff message; on 3.2.20 and earlier a threaded reply in a per-conversation channel was silently discarded, and from 3.2.21 it reaches the visitor. Messages Slack tags with a subtype — an edited reply, a file, snippet or image upload — are never relayed; from 3.2.21 the agent sees a short note in the channel explaining how to get the message through, and the drop is logged when Debug Mode is on. If your shared channel is private, Slack sends replies as message.groups events, which the app manifest does not subscribe to: add the groups:history scope, subscribe to message.groups alongside message.channels, and reinstall the app. From 3.2.21 the Slack settings screen warns you when the shared channel it is pointed at is private.
Also added in 3.2.15: an optional setting to archive a conversation's Slack channel when an agent ends the chat, so per-visitor channels stop piling up. It is off by default.
Step 1 — Download the Slack app manifest
Download the ready-made app manifest. It pre-fills the bot user, permission scopes, and request URLs so you don't have to configure them by hand:
Step 2 — Create the Slack app from the manifest
- Go to api.slack.com/apps and click Create New App → From a manifest.
- Choose your workspace, open the YAML tab, and paste the contents of
website-to-slack.txt. - Replace both
https://example.complaceholders with your own domain, so the URLs readhttps://YOUR-SITE.com/wp-json/mxchat/v1/slack-messagesandhttps://YOUR-SITE.com/wp-json/mxchat/v1/slack-interaction. - Click Create, then Install to Workspace and approve the permissions.
Step 3 — Copy your Bot Token
Open OAuth & Permissions and copy the Bot User OAuth Token — it starts with xoxb-. While you're in the app settings, also grab the Signing Secret from Basic Information → App Credentials.
Step 4 — Connect Slack in WordPress
In your WordPress admin, go to Settings → Integrations → Slack and fill in:
- Live Agent Status — turn it On.
- Slack Bot OAuth Token — the
xoxb-…token from Step 3. - Slack Agent User IDs — the member ID of each agent who should be pulled into chats, one per line (e.g.
U1234567890). In Slack, open a profile, then More → Copy member ID. - Slack Secret Key — your app's Signing Secret; it verifies that incoming requests really came from Slack.
- Slack Webhook URL — your Incoming Webhook URL, used for agent notifications.
- Notification Message — what the visitor sees once an agent has been pinged.
- Away Message — shown when Live Agent is off, so the bot keeps helping on its own.
Then click Test Slack Connection to confirm the token authenticates and can create channels.
Step 5 — Turn on the handoff Action
Go to Settings → Actions, enable Slack Live Agent, and add the trigger phrases that should escalate a chat — for example "talk to a human", "speak to an agent", or "live support". Save, and the handoff is live.
Alternatively, enable Hand Off to Live Agent (Slack) under Actions → AI Tools and let the model decide when to escalate, with no phrase list to maintain. From 3.2.19 that tool ships with its usage note already filled in — use this when the visitor has asked something you cannot answer from the knowledge base, or has asked twice about the same unresolved problem — so switching it on is enough on its own.
What the agent sees
The New Live Agent Request posted into Slack carries the session ID, the WordPress user ID, the visitor's name and email if either was captured, then the last five messages of the conversation as a quoted Recent Conversation block, and finally the message that triggered the handoff. It is the last five turns rather than the whole transcript — open MxChat → Transcripts and search the session ID printed in the Slack message for the full conversation. From 3.2.21 the count is filterable with mxchat_handoff_history_count (one filter for Slack, Telegram and the webhook destination; Telegram asks for 10).
Required OAuth scopes
The manifest already grants everything the integration needs. If you ever build the app by hand instead, add these Bot Token Scopes under OAuth & Permissions → Scopes, then reinstall the app:
channels:manage·channels:read·chat:write·chat:write.public·groups:write·users:read
The manifest grants a slightly wider set — it also adds
commands,im:write,incoming-webhook,app_mentions:read,channels:history, andgroups:read— so every handoff feature works out of the box. When in doubt, use the manifest.
Troubleshooting Slack handoff
- Nothing happens when a visitor asks for an agent — confirm Live Agent Status is On, the Bot OAuth Token is saved, and the Slack Live Agent Action has trigger phrases. Run Test Slack Connection.
- Agents aren't added to the channel — make sure the Agent User IDs are member IDs (they start with
U), one per line, and that the app has thechannels:manageandchannels:readscopes. - Agent replies don't reach the visitor — in Slack, check that the Event Subscriptions request URL points to
https://YOUR-SITE.com/wp-json/mxchat/v1/slack-messagesand shows as Verified. If that is right and replies still vanish, see Where to reply above: a thread reply in a per-conversation channel (fixed in 3.2.21), an edited or file-based reply, or a private shared channel without themessage.groupssubscription.
Telegram handoff
The Telegram destination has its own guide — MxChat Telegram Integration — covering the bot, the supergroup with Topics, and the webhook secret. What changed in 3.2.21: the handoff now shares the last 10 messages (up from five), labelled with the count and split into several Telegram messages when the history is long, where before a conversation over Telegram's message limit could drop the whole handoff card without a trace; ending a conversation — with #close in the topic or by closing the topic in Telegram — now retires that topic, so the visitor's next request opens a fresh one instead of posting into a closed topic agents cannot reply in; any message Telegram refuses to deliver is shown on the Telegram settings screen with Telegram's own explanation; and when your site rejects Telegram's incoming requests — the usual cause is Cloudflare or a reverse proxy in front of a webhook registered without a secret — the Telegram settings screen and a dashboard notice say how many were rejected, when, why, and how to fix it. The Open Telegram settings button on the webhook-security notice now opens the Telegram tab rather than the onboarding screen.
Displaying the Chatbot
Turn the chatbot on for your whole site under Settings → Display → Auto-Display Chatbot, or place it manually with a shortcode:
[mxchat_chatbot floating="yes"]— a floating widget in the bottom corner.[mxchat_chatbot floating="no"]— an inline embedded chat anywhere on a page.
The Display tab also controls chat persistence, link behavior, the chat window's text and labels, and appearance. To deploy the same chatbot on a non-WordPress site, see the MxChat Anywhere add-on.
Visitors can save a conversation with the Download Transcript item in the chat window menu. Show or hide it under Settings → Display → Visibility → Show Download Transcript Button (on by default). You can also add a Start new chat item to the same menu — it clears the current conversation and begins a fresh session (after a quick confirm) — by turning on Settings → Display → Show Start-New-Chat Button (off by default; rename the item with the adjacent label field). With Chat Persistence on, 3.2.21 fixes what a returning visitor sees: Start new chat now leaves only your greeting, and a restored conversation keeps the greeting above it — on earlier versions a returning visitor could be left with one old reply and no greeting. While the bot is streaming an answer, the send button becomes a Stop control — click it to end the stream and keep the partial reply.
Pre-chat lead capture. Settings → Chatbot → Lead Capture → Require Email to Chat puts a name-and-email form in front of the first message. Since 3.2.20 the form can carry a Consent Checkbox with your own label and Privacy Policy link, optionally required and enforced on the server, and each capture records whether it was ticked, when, and the exact label shown — visible in the Leads tab, the CSV export and privacy exports. From 3.2.22 two more toggles on the same screen: Also Show for Logged-In Users shows the form to signed-in visitors too, pre-filled from their profile (by default they skip it, which on a membership or LMS site meant no lead and no consent was ever captured), and Require Email Address off makes the email field optional, so you can collect a name and consent alone. Leads captured either way appear in the Leads tab, the CSV export and the GET /leads API endpoint.
The floating launcher button is fully keyboard-operable: Tab to focus it, Enter or Space to open the chat, and Esc to close it — focus returns to the launcher on close (WCAG 2.1 Level A).
Loading chatbot files only where the chatbot appears (added in 3.2.15). By default MxChat loads its CSS and JavaScript on every page. Core 3.2.15 adds an optional performance setting that loads them only on pages where the chatbot actually appears — useful when a performance audit flags MxChat under "reduce unused CSS and JavaScript". It is off by default, so existing sites are unchanged until you turn it on. If you use the MxChat Triggers add-on, enabling this is safe: a trigger's job is to open the chat widget, so a trigger on a page with no widget was already non-functional.
Privacy & Data Requests (GDPR)
WordPress ships its own data-subject tooling at Tools → Export Personal Data and Tools → Erase Personal Data. Since core 3.2.16, MxChat registers with it — so when you run a request against your site, chat conversations are included automatically. There is nothing to configure and no separate MxChat screen to remember.
This matters because chat is a free-text field. Visitors paste order numbers, addresses and account details into it, and MxChat also records the email and name captured during a conversation, the page the chat started on, and — for anonymous visitors — the IP address used as their identifier. Before 3.2.16 a site owner could run WordPress's own tool, get a clean report, and send it while every chat transcript for that person sat untouched.
How a person is matched. WordPress hands the tools an email address. MxChat matches conversations three ways:
- the email captured on the conversation matches the address, and
- when that address belongs to a registered WordPress account, the conversation's user ID or username matches that account.
The second rule is what catches logged-in conversations where the visitor never typed their email into the chat. The practical limit is worth knowing: a purely anonymous visitor who never gave an email and has no account is identified only by IP, and WordPress's privacy tools are keyed by email address — so there is no handle to match them on. That is a property of the WordPress tooling, not of MxChat.
What an export contains. One item per conversation, grouped under Chat Conversations (MxChat): the session ID, when it started and ended, the page it started on, any email/name/identifier on record, and then every message in order, each labelled with its timestamp and whether it came from the visitor, the AI, or a live agent. Exports are paginated (10 conversations per request), so a heavily-used site completes without timing out.
What an erasure removes. For each matching conversation: the transcript rows, any stored translations of them, the saved conversation history and captured name/email held against that session, and the temporary records from Chat with PDF / Word document uploads — including deleting the uploaded file itself from disk. Erasures run 25 conversations per batch.
Keeping a conversation on legal hold. If your site has to retain a specific conversation despite an erasure request, filter it:
add_filter('mxchat_privacy_erase_session', function($erase, $session_id, $email) {
// return false to retain this conversation
return $erase;
}, 10, 3);
A retained conversation is reported back in the erasure result, never silently kept — WordPress's report will say it was retained by a site-specific policy, which is what you need for your own records.
Suggested privacy-policy text. MxChat also adds a suggested section to Settings → Privacy → Privacy Policy Guide, describing what the chat stores, that it stays in your own database rather than a third-party chat service, how long it is kept, and that it is covered by export and erasure requests. Copy it into your policy and edit to taste.
This is separate from transcript retention (Settings → Transcripts), which deletes conversations in bulk after a set period. Retention is a time-based sweep; this is a named individual's access or erasure request. You want both.
Session storage and automatic cleanup (3.2.18)
Every conversation carries a little working state — which bot it belongs to, a captured name or email, live-agent status. Until 3.2.18 each of those was written to the WordPress options table as its own row and never cleaned up, so a busy site accumulated thousands of them and some were loaded on every single page view. From 3.2.18 that state lives in its own table, {prefix}mxchat_sessions, and existing rows are moved across automatically in background batches after you update — there is nothing to run and no setting to change.
Sessions untouched for 30 days are now deleted on their own. Two things trigger the sweep, deliberately: a daily maintenance event, and a capped opportunistic pass on the write path that runs at most once an hour and removes a bounded number of rows. That second route is what makes the cleanup survive a site where WP-Cron never runs — a common state on hosts that disable it without substituting a real system cron.
To keep sessions longer or shorter, filter the window:
add_filter('mxchat_session_retention_days', function($days) {
return 90;
});
A value of zero or less is ignored rather than obeyed, since it would sweep conversations that are still live. This is about the chatbot's own per-session working state — your transcripts are governed separately under Settings → Transcripts.
REST API
MxChat exposes a bearer-token-authenticated REST API for headless access. Generate and manage your token under Settings → API Access. Endpoints: GET /health, GET and DELETE /transcripts, POST /knowledge to push content, and from 3.2.22 DELETE /knowledge — remove entries by source_url, singly or up to 50 at a time, so a document deleted in SharePoint, Drive or your CMS can be taken out of the chatbot by your sync job (a URL that is not stored is reported as nothing removed, not an error) — and GET /leads, which reads lead-capture submissions with paging, a since filter, search and a status filter, so leads can be synced into a CRM or spreadsheet automatically. The API Access screen documents every endpoint in one place with ready-to-run examples for both new calls. The chat widget itself also fetches a fresh per-request security token from /wp-json/mxchat/v1/nonce, which keeps the first message reliable even behind full-page caches.
For a Model Context Protocol (MCP) interface to your install — so Claude, ChatGPT, and other agents can talk to MxChat natively — see the MxChat MCP Server add-on.
For developers (3.2.22). Add-ons can put a button in the chat toolbar with the mxchat_chat_toolbar_items filter, and the mxchat:toolbar-ready and mxchat:opened page events replace watching the page or running a request on every view — the WooCommerce cart button is the first to use it. Add-ons can also append to a chat transcript with save_session_message, shape what humans read with mxchat_transcript_user_message and mxchat_ai_conversation_history, and add sections to the Telegram and Slack handoff card with mxchat_handoff_card_sections. All of these are documented on the developer hooks & filters page.
Troubleshooting
Security update — 3.2.16. This release hardened how MxChat validates chat session identifiers across the plugin, and tightened the permission checks around its admin scripts and admin-only actions so they load and run only for users who can manage plugin options. If your site sends automatic transcript emails, update.
- "Invalid API key" / no replies — re-check the key under Settings → API Keys; make sure it matches the provider of your selected chat model.
- Bot doesn't know my content — confirm the content is indexed under Settings → Knowledge, and that an embedding model + key are configured. Lower the Similarity Threshold if good content isn't being matched.
- "Access denied" on the first message behind a cache — make sure you're on the current version; MxChat fetches a per-request nonce that resolves this for WP Rocket, LiteSpeed, FlyingPress, W3 Total Cache, and Cloudflare APO.
- A model shows an error after a provider change — MxChat auto-recovers retired models on the next admin load; if a specific model errors, re-select a current one under Select AI Model.
- An occasional dropped or failed reply — MxChat automatically retries on transient provider errors (5xx, rate-limit, and overload responses) for both streaming and standard chat, so brief provider hiccups usually recover on their own without a visible error.
- A visitor sees an AI error in the chat — when a call still fails after retries (a bad key, a hard rate-limit, a connection timeout, or a provider outage), MxChat shows a short, readable message in the chat rather than a raw error dump, and never exposes internal details or your API key. The specifics are in your server log for you to diagnose. Since 3.2.15 those messages carry the provider's own explanation — including the exact model name xAI could not find — instead of a generic "Unknown error".
- An empty chat bubble — when a provider returns a successful but empty reply, MxChat (since 3.2.15) shows a clear message asking the visitor to try again instead of an empty bubble. Streaming replies close out the same way.
- A knowledge base import failed and the error didn't say why — fixed in 3.2.16. Import errors now carry the embedding provider's own reason (an invalid API key, exhausted credit, a model your key can't use), name the model, and say which stage failed. In particular,
Failed to store any chunksnow continues with either "every chunk failed to embed" or "embeddings generated but storage failed" — the first points at your embedding API key, the second at your Pinecone index or database. On earlier versions both cases produced the same sentence, which is why a bad key so often sent people to rebuild a Pinecone index that was fine. - Streaming replies arrive all at once after a pause — fixed in 3.2.16 for sites behind a buffering proxy such as nginx; replies stream word by word again, and four PHP warnings per affected chat go with it.
- Quick Question buttons render too small — fixed in 3.2.16. In 3.2.15 the new theme-protection styles let the list squeeze its buttons to fit the box instead of scrolling; they are back to their normal size with the scrollbar restored.
- A Loops setting the message told you to find isn't on that screen — fixed in 3.2.16. Both email-capture messages now name the API Keys tab and link straight to it.
- Japanese, Chinese or Thai content came back empty or mangled after an import — fixed in 3.2.17. Content in scripts without spaces between words is no longer erased, split into oversized chunks, or stripped of rare characters on the way into the knowledge base. Re-import anything you indexed before updating.
- A toggle saved but never showed the "saved" confirmation — fixed in 3.2.17 for the hybrid keyword boost and smart asset loading toggles. The setting was being stored correctly; only the confirmation was missing, which made both look broken.
- The WordPress content import window was cut off on a phone — fixed in 3.2.17; the import dialog now fits small screens with its buttons reachable.
- The bot answers as if the knowledge base were empty, and you use OpenAI Vector Store — fixed in 3.2.18. Every Vector Store search was rejected by OpenAI and the error was discarded, so answers came back with no retrieved content and nothing was logged. Update; no re-index is needed. See the note above.
- A sitemap import failed and the status area was blank — fixed in 3.2.18; sitemap imports now name the reason, including an API key that lacks the permission the import needs. Knowledge base import errors from OpenAI, Gemini and Voyage also pass along the provider's own explanation instead of a generic invalid-key message.
- A PDF shared in chat came back "empty or unsupported" — fixed in 3.2.18. When an embedding request failed part-way through a document, the unreadable pages were stored anyway; they are now skipped and recorded in the Debug Mode log, and a file where no page can be read reports the real reason instead of claiming the file is empty.
- A tick mark in the content selector was invisible — fixed in 3.2.18; selected items were drawing white on white and now show a filled checkbox.
- Transcripts labelled everything "AI Assistant" — fixed in 3.2.15. Conversations a human took over now show as Live Agent in the Transcripts viewer and in emailed transcripts, so you can tell which replies came from your team and which came from the bot. Nothing to configure; update to 3.2.15 or later.
- Hebrew, Arabic or other right-to-left PDFs imported with the text reversed — fixed in 3.2.19, and a new WP-CLI repair command fixes entries imported before the update in place, so you do not have to re-import them.
- Notification emails or transcripts stopped arriving after you entered two addresses — fixed in 3.2.19, and this one failed silently, so it is worth checking. On earlier versions the Notification Email field held one address; entering
[email protected], [email protected]was stored as[email protected], which passed WordPress's own validity check, so nothing looked wrong and every alert went to a domain that does not exist. From 3.2.19 the field takes up to five comma-separated addresses, refuses an invalid one with a message naming it, and never silently accepts a mangled list. - A YouTube card appeared under an answer it had nothing to do with — fixed in 3.2.19. A video card used to attach whenever a matching source was retrieved, with no relevance gate. There is now a match threshold setting, and video cards can be switched off entirely.
- The chatbot quotes product prices in the wrong currency — fixed in 3.2.19 for newly indexed content. WooCommerce prices are now indexed in your store's base currency with the currency code, and the bot no longer mixes two currencies in one reply. Products indexed before the update keep the old text, so re-run the WordPress Content import for your products after updating.
- You lost settings edits by navigating away mid-change — improved in 3.2.19. Changed fields show an Unsaved marker, leaving mid-edit asks for confirmation, and the edits are handed to the browser for saving if you leave anyway.
- Imported content lost currency symbols, or Arabic/Hebrew/Hindi/Thai marks — fixed in 3.2.19, along with leftover HTML character codes now being converted to readable text before indexing. Re-import the affected content to clean up existing entries.
- A draft post was indexed under your homepage address — fixed in 3.2.19 for drafts published by import tools or scripts.
- A Telegram agent can read a returning visitor's messages but cannot reply — fixed in 3.2.21. Ending a conversation used to leave the topic mapped, so that visitor's next request posted into the closed topic, which Telegram gives no compose box. Ending a conversation, from MxChat or from Telegram, now retires the topic and the next request opens a fresh one.
- A Telegram handoff arrived with no conversation history, or not at all — fixed in 3.2.21. A long conversation could exceed Telegram's message limit and take the whole handoff card with it; the history is now sent in parts as readable text, and any delivery Telegram refuses is shown on the Telegram settings screen with its reason.
- Telegram replies stopped arriving after you put the site behind Cloudflare — the webhook was registered without a secret, so every request is rejected as coming from outside Telegram's ranges. From 3.2.21 the Telegram settings screen and a dashboard notice count the rejections and say why; set a webhook secret and re-register the webhook from that screen.
- A Slack agent replied in a thread and the visitor never saw it — fixed in 3.2.21 for per-conversation channels. In a shared channel, replies must always go inside the conversation's thread.
- Start new chat left one old reply on screen and no greeting — fixed in 3.2.21 for sites with Chat Persistence on.
- The Pro & Extensions button for an add-on you have not installed opened the same page as Documentation — changed in 3.2.21: it now reads Get the ZIP from My Account and opens your account's Downloads page, where the add-on ZIPs live.
- The chatbot recommends past, expired events — fixed in 3.2.22: the current date and time in your site's timezone now travel with every message (see Behavior above). On earlier versions nothing told the model the date.
- A knowledge entry restricted to a custom role was readable by every signed-in visitor — fixed in 3.2.22. Restrictions to the five built-in roles were never affected.
- Choosing Media in the WordPress Content importer showed nothing — fixed in 3.2.22; it now lists the PDF, Word, text and Markdown files in your library.
- With Pinecone, Knowledge Entries says (50) however much you import — fixed in 3.2.22; the heading now shows Pinecone's own vector count. Nothing was ever missing from the index.
- A video or audio player on the page starts playing when a visitor sends a message — fixed in 3.2.22 for sites with Contextual Awareness on; the page text is read from an inert copy, gathered once per page.
- Underscored words — file names, SKUs,
_PLACEHOLDER_tokens — lost their underscores and turned italic — fixed in 3.2.22 (see Markdown above). - Daily, weekly or monthly message limits never seemed to bite — fixed in 3.2.22; counters used to be cleared hourly and keyed on a client-supplied address header.
- A tool-using conversation ended in a provider error once several tools had run — fixed in 3.2.22; the function-calling loop no longer sends an invalid request when the per-turn tool budget is reached.
- Minimum versions — 3.2.22 declares WordPress 5.3 and PHP 7.4 as its minimums, matching what the code has required for some time; every MxChat add-on already required PHP 7.4.
Still stuck? Ask the Documentation Bot — it has access to the full MxChat source and every plugin's docs — or open a ticket.
Last reviewed by Sage on 2026-09-21 (MxChat core 3.2.22) — documented the opt-in Pinecone document index with full-text search (Create index for me, Check index, copy-migration, Hybrid keyword boost on Pinecone, Vector/Keyword/Both labels in Testing), the automatic current date and time line and the {current_date} / {current_datetime} placeholders, role restrictions for custom roles and the per-page Knowledge base access setting, Media Library import and auto-sync of PDF, Word, text and Markdown files, the pre-chat form for logged-in visitors and the optional email field, DELETE /knowledge by source URL and GET /leads, the Gemini 3.8/3.7/3.6 Flash models and the low thinking level, the toolbar and transcript developer hooks, and troubleshooting for the custom-role leak, the empty Media importer, the Pinecone (50) count, autoplaying media under Contextual Awareness, underscores turning italic, hourly-resetting rate limits and the function-calling budget error. Previously reviewed 2026-09-12 (MxChat core 3.2.21) — documented where Slack agents must reply in each channel mode now that thread replies in per-conversation channels are relayed, the note agents see when an edited or file-based reply is dropped, the private-shared-channel warning and the message.groups subscription it asks for, the mxchat_handoff_history_count filter, the Telegram changes (ten-message history sent in parts, closed topics retired on #close or when closed from Telegram, delivery failures and webhook rejections surfaced on the Telegram settings screen), the Chat Persistence greeting fix for Start new chat, and the Pro & Extensions button that now opens your Downloads page. Previously reviewed 2026-08-29 (MxChat core 3.2.20) — documented the new Strip Unapproved Links setting under Settings, Behavior: the link guard is now its own control instead of riding Citation Links, so fabricated URLs are removed even with citations off, while approved citations, real pages on this site and integration-returned links such as WooCommerce product URLs are always kept. Previously reviewed 2026-08-16 (MxChat core 3.2.19) — documented the daily model-liveness check and the automatic migration off retired Claude models, automatic Anthropic prompt caching, the refreshed xAI Grok lineup, AI Tool runs now recorded per message in Transcripts (sensitive tools logging only that they fired), the live-agent handoff tools shipping with their usage hint prefilled, what the Slack handoff actually sends an agent, and troubleshooting for right-to-left PDF imports, the multi-address Notification Email field, mismatched YouTube cards, WooCommerce currency indexing, unsaved-settings protection and homepage-addressed drafts. Previously reviewed 2026-08-09 (MxChat core 3.2.18) — documented that OpenAI Vector Store retrieval was failing silently on earlier versions and is fixed (no re-index needed), the new per-conversation mxchat_sessions table with automatic 30-day cleanup that works even where WP-Cron never runs and its mxchat_session_retention_days filter, and troubleshooting for blank sitemap-import errors, part-way PDF embedding failures and the invisible content-selector tick. Previously reviewed 2026-08-06 (3.2.17) — documented that custom and local embedding providers such as Ollama and LM Studio now work end to end with no cloud API key, that the hybrid keyword boost moved to Knowledge → Chunking & Retrieval, that scheduled posts are indexed when they go live, and troubleshooting for Japanese/Chinese/Thai imports, the missing toggle save confirmation and the cut-off import window. Every settings tab also now has its own shareable link that opens directly on that tab. Previously reviewed 2026-08-03 (3.2.16) — added the Privacy & Data Requests section covering MxChat's integration with WordPress's export and erasure tools, the hybrid keyword boost for the WordPress-database knowledge base, the wp mxchat prune-unpublished command and reliable removal of unpublished content, retirement dates in the model picker plus the GPT-5.1 Chat Latest / GPT-5.3 Chat migration to GPT-5.6 Sol on August 10, the persistent admin notice when a provider rejects your model, the plainer "nothing relevant in the knowledge base" handling, and troubleshooting for import errors that now name the reason and the failing stage, proxy-buffered streaming, Quick Question button sizing and the Loops message wording. Spotted an issue? Open a ticket and we'll patch the doc.