diff --git a/assistant/widget.mdx b/assistant/widget.mdx
index b5fcc4f65..0e754255b 100644
--- a/assistant/widget.mdx
+++ b/assistant/widget.mdx
@@ -3,7 +3,6 @@ title: "Mintlify widget"
sidebarTitle: "Widget"
description: "Install and configure the Mintlify widget to embed the AI assistant trained on your content in any website or web application."
keywords: ["assistant", "chat", "embed"]
-mode: "wide"
---
import { AssistantWidgetPlayground } from "/snippets/assistant-widget-playground.jsx";
@@ -16,7 +15,7 @@ The [assistant](/assistant) answers questions on your Mintlify site. To embed th
Add the widget to any website or web application with a hosted script. The widget owns its trigger and renders inside a closed Shadow DOM, which prevents your application styles from affecting the widget.
-The only required browser option is the public widget ID. Manage the enabled state, allowed origins, attachments, and bot protection in your dashboard. Set embed-specific starter questions and a support email in the browser configuration.
+The only required browser option is the public widget ID. Manage the enabled state, allowed origins, attachments, and bot protection in your dashboard. Set embed-specific starter questions, a support email, and retrieval filters in the browser configuration.
## Prerequisites
@@ -39,7 +38,7 @@ Use the playground to configure the presentation, visual options, and observer h
After you add the generated code to your site, reload the page. Confirm the trigger appears, then click it and send a test question to verify the connection.
-
+
Module scripts defer and run in document order. Keep the hosted loader before the initialization block when you install the widget with HTML, or the widget fails to mount.
@@ -95,7 +94,7 @@ Event metadata and requests include the `source` value, which lets you distingui
## Update a mounted widget
-Use `update()` to change appearance, labels, support email, starter questions, or hooks without clearing the current conversation. Only the supplied fields change.
+Use `update()` to change appearance, labels, support email, starter questions, retrieval filters, or hooks without clearing the current conversation. Only the supplied fields change.
```js
await window.MintlifyAssistant.update({
@@ -148,7 +147,8 @@ Pass this object to `init()`.
| `appearance` | [`AssistantAppearance`](#assistantappearance) | Visual and presentation overrides. |
| `labels` | [`AssistantLabels`](#assistantlabels) | Customer-facing text overrides. |
| `supportEmail` | string | Sets the support address shown in the widget toolbar for this embed. |
-| `starterQuestions` | string[] | Sets up to three empty-state prompts for this embed. |
+| `starterQuestions` | string[] | Sets up to three empty-state prompts for this embed. |
+| `filter` | object | Restricts retrieval by language or version. |
| `hooks` | [`AssistantHooks`](#assistanthooks) | Event and error observers. |
### `AssistantAppearance`
@@ -225,6 +225,7 @@ Pass this object to `update()`. Every field is optional, and `null` restores its
| `labels` | [`AssistantLabels`](#assistantlabels) or `null` | Deep-patches customer-facing text. |
| `supportEmail` | string or `null` | Changes the support address. Pass `null` to remove it. |
| `starterQuestions` | string[] or `null` | Changes up to three prompts. Pass `null` to restore an empty list. |
+| `filter` | object or `null` | Deep-patches retrieval filters. Pass `null` to clear them. |
| `hooks` | [`AssistantHooks`](#assistanthooks) or `null` | Deep-patches event and error observers. |
## Browser API
@@ -241,6 +242,25 @@ Pass this object to `update()`. Every field is optional, and `null` restores its
Conversation snapshots remain private to the widget. Each method resolves to `void`.
+## Analytics and privacy
+
+The widget loads Mintlify's internal analytics client in a separate lazy chunk from the widget CDN after initialization begins, then sends events to `https://ph.mintlify.com`. Initialization does not wait for analytics, and an analytics import, initialization, or capture failure does not affect widget behavior.
+
+Mintlify collects:
+
+- Installation and open or closed state transitions
+- Question submission origin, attachment count, request duration, and outcome
+- Opaque widget-session, open-session, and request IDs
+- Server-issued thread and message IDs
+- Successful starter-question, option, source, suggestion, copy, and support-link interactions using indexes or destination categories
+- Feedback polarity, widget ID and versions, presentation surface, anonymous-versus-signed identity mode, and the embedding hostname
+
+Mintlify does not collect prompts, answers, starter-question or option text, support email, identity tokens, thread keys, CAPTCHA values, raw identities, full URLs, referrers, query parameters, campaign parameters, or error messages.
+
+The analytics client uses memory-only persistence. It does not create person profiles or identify visitors, and it disables automatic capture, page views, page leave, session replay, surveys, feature flags, performance collection, heatmaps, exception capture, campaign storage, referrer storage, and geolocation enrichment.
+
+Analytics events are internal to Mintlify, are not part of the public widget configuration, and do not change [`hooks.event`](#assistanthooks).
+
## Content Security Policy
If your site uses a Content Security Policy, allow the origins required by your enabled widget features:
@@ -248,7 +268,8 @@ If your site uses a Content Security Policy, allow the origins required by your
| Directive | Source | Required for |
| -------------------------------------------- | ----------------------------------- | --------------------------- |
| `script-src` | `https://cdn.jsdelivr.net` | Widget loader and runtime |
-| `connect-src` | `https://api.mintlify.com` | Widget API |
+| `connect-src` | `https://api.mintlify.com` | Configuration, messages, and feedback |
+| `connect-src` | `https://ph.mintlify.com` | Internal widget analytics |
| `style-src` | `https://cdn.jsdelivr.net` | Widget style sheet |
| `font-src` | `https://cdn.jsdelivr.net` | Optional bundled Inter font |
| `script-src`, `connect-src`, and `frame-src` | `https://challenges.cloudflare.com` | Turnstile bot protection |
@@ -257,4 +278,6 @@ If your site uses a Content Security Policy, allow the origins required by your
A strict `script-src` policy must still authorize both the loader and initialization script. Passing `nonce` to `init()` propagates it only to resources the widget creates after initialization.
-
+`https://api.mintlify.com` remains required when you use the hosted endpoint because the browser sends configuration, message, and feedback requests to it. If you set a custom `endpoint`, allow that origin instead.
+
+The CSP `frame-ancestors` directive controls which sites may embed a document. It does not authorize outgoing browser requests and is unrelated to the widget, which renders in Shadow DOM instead of an iframe. CAPTCHA providers can embed their own frames and separately require the `frame-src` sources in the table.
diff --git a/playground.css b/playground.css
index 127553fc2..897d932be 100644
--- a/playground.css
+++ b/playground.css
@@ -1,34 +1,3 @@
-@media (min-width: 1024px) {
- html[data-current-path="/assistant/widget"] #content-area {
- position: relative;
- max-width: 1800px !important;
- margin-inline: auto;
- /* Percentage padding resolves against the parent, so cap it at half of the 1800px max-width */
- padding-right: calc(min(50%, 900px) + 1rem);
- }
-
- html[data-current-path="/assistant/widget"] #content {
- position: static;
- }
-
- html[data-current-path="/assistant/widget"] [data-assistant-preview] {
- position: absolute;
- inset: 0 1.5rem 0 auto;
- width: calc(50% - 2.5rem);
- }
-}
-
-html[data-current-path="/assistant/widget"]
- div:has(> iframe[title="Live Assistant Widget preview"]) {
- min-height: 0;
- flex: 1 1 0%;
-}
-
-html[data-current-path="/assistant/widget"]
- iframe[title="Live Assistant Widget preview"] {
- height: 100%;
-}
-
/* The widget playground embeds /assistant/widget-preview in its preview
iframe. The suffix match keeps localized paths covered. Hide every piece of
docs chrome so only the widget renders, and keep the document transparent
diff --git a/snippets/assistant-widget-playground.jsx b/snippets/assistant-widget-playground.jsx
index 48ca536fa..d2e93fe3b 100644
--- a/snippets/assistant-widget-playground.jsx
+++ b/snippets/assistant-widget-playground.jsx
@@ -1,4 +1,4 @@
-export const AssistantWidgetPlayground = ({ children, CodeBlockComponent }) => {
+export const AssistantWidgetPlayground = ({ CodeBlockComponent }) => {
// Mintlify evaluates snippet exports independently, so shared values must stay in this scope.
const EXAMPLE_WIDGET_ID = "YOUR_WIDGET_ID";
const EMBED_URL =
@@ -40,6 +40,10 @@ export const AssistantWidgetPlayground = ({ children, CodeBlockComponent }) => {
{ value: "center", label: "Center" },
{ value: "end", label: "End" },
];
+ const BOOLEAN_OPTIONS = [
+ { value: "off", label: "Off" },
+ { value: "on", label: "On" },
+ ];
const INSTALL_OPTIONS = [
{ value: "html", label: "HTML" },
{ value: "next", label: "Next.js" },
@@ -97,8 +101,8 @@ export const AssistantWidgetPlayground = ({ children, CodeBlockComponent }) => {
}, []);
useEffect(() => {
- // SPA navigations can mount this page before the sticky/absolute preview
- // host has a laid-out box. Delay the iframe until the host has size.
+ // SPA navigations can mount this page before the preview host has a
+ // laid-out box. Delay the iframe until the host has size.
const host = previewHostRef.current;
if (!host) return undefined;
@@ -120,95 +124,55 @@ export const AssistantWidgetPlayground = ({ children, CodeBlockComponent }) => {
return () => observer.disconnect();
}, []);
- const classNames = (...classes) => classes.filter(Boolean).join(" ");
-
- const renderSegmentedControl = ({
- ariaLabel,
- onChange,
- options,
- threeColumns = false,
- value,
- }) => (
-