+ )}
+ >
+ );
+}
+```
+
+### Configure environment variables
+
+Add your assistant API token to your environment variables:
+
+```bash .env
+REACT_APP_MINTLIFY_TOKEN=mint_dsc_your_token_here
+```
+
+
+ The environment variable name depends on your framework. Common formats include:
+ - Create React App: `REACT_APP_MINTLIFY_TOKEN`
+ - Next.js: `NEXT_PUBLIC_MINTLIFY_TOKEN`
+ - Vite: `VITE_MINTLIFY_TOKEN`
+
+
+### Add the widget to your app
+
+Import and render the assistant widget in your application. Replace `docs.yourcompany.com` with your documentation domain.
+
+```jsx App.jsx
+import { AssistantWidget } from './components/AssistantWidget';
+
+function App() {
+ return (
+
+ {/* Your existing app content */}
+
+ {/* Add the assistant widget */}
+
+
+ );
+}
+
+export default App;
+```
+
## Test the widget
+1. Start your development server:
+ ```bash
+ npm start
+ ```
+2. Open your application in a browser.
+3. Click the assistant button in the bottom-right corner.
+4. Ask a question that requires searching your documentation, such as "How do I get started?"
+
+### Verify the assistant
+
+Check the following to confirm the widget is working:
+
+- The chat panel opens when you click the toggle button.
+- Your question appears in the chat as a user message.
+- The assistant responds with relevant information from your documentation.
+- Source links appear below the response and navigate to your docs when clicked.
+- Follow-up questions maintain the conversation context.
+
+## Optional enhancements
+
+### Filter by documentation section
+
+Limit the assistant's responses to specific sections of your documentation by adding a `filter` parameter to the request body. For example, to only search the API reference section, add `filter: '/api-reference'`.
+
+```jsx
+const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
+ api: `https://api.mintlify.com/v1/assistant/${domain}/message`,
+ headers: {
+ 'Authorization': `Bearer ${process.env.REACT_APP_MINTLIFY_TOKEN}`,
+ },
+ body: {
+ threadId: threadId,
+ filter: '/api-reference', // Only search API reference section
+ },
+ // ... rest of config
+});
+```
+
+### Track user sessions
+
+Pass a user identifier to track sessions and provide personalized assistance.
+
+```jsx
+body: {
+ threadId: threadId,
+ fp: userId, // User fingerprint or ID
+},
+```
+
+### Customize styling
+
+The component uses Tailwind CSS classes. Customize the appearance by modifying the class names or replacing them with your own CSS solution.
+
## Troubleshooting
+
+### Widget not appearing
+
+- Verify the component is imported and rendered in your app.
+- Check that Tailwind CSS or your styling solution is properly configured.
+- Ensure the z-index values do not conflict with other fixed elements.
+
+### 401 authentication error
+
+- Verify your API token starts with `mint_dsc_`.
+- Check the token is correctly set in your environment variables.
+- Confirm you are using the public assistant API token, not the admin API key.
+- Restart your development server after adding environment variables.
+
+### No responses from assistant
+
+- Verify your documentation domain is correct (do not include `https://`).
+- Check that your Mintlify plan includes the assistant feature.
+- Confirm your documentation site is published and accessible.
+
+### Thread context not maintained
+
+- Verify the `threadId` is being stored and passed correctly.
+- Check that the `onFinish` callback is setting the thread ID from the response.
+- Ensure the `threadId` state persists between messages.
From 9f98c810ea556bf2795f8d024e16bc15341be342 Mon Sep 17 00:00:00 2001
From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com>
Date: Mon, 20 Oct 2025 11:27:25 -0700
Subject: [PATCH 05/36] review code samples
---
guides/assistant-widget.mdx | 103 +++++++++++++++++++++---------------
1 file changed, 59 insertions(+), 44 deletions(-)
diff --git a/guides/assistant-widget.mdx b/guides/assistant-widget.mdx
index fe0c4d915..cc32d18f4 100644
--- a/guides/assistant-widget.mdx
+++ b/guides/assistant-widget.mdx
@@ -52,7 +52,7 @@ Create a new file `AssistantWidget.jsx` (or `.tsx` if using TypeScript) in your
import { useChat } from '@ai-sdk/react';
import { useState } from 'react';
-export function AssistantWidget({ domain }) {
+export function AssistantWidget({ domain, userId = 'anonymous' }) {
const [isOpen, setIsOpen] = useState(false);
const [threadId, setThreadId] = useState(null);
@@ -62,14 +62,19 @@ export function AssistantWidget({ domain }) {
'Authorization': `Bearer ${process.env.REACT_APP_MINTLIFY_TOKEN}`,
},
body: {
+ fp: userId,
threadId: threadId,
},
- onFinish: (message) => {
- // Store thread ID from first response to maintain conversation history
- if (!threadId && message.threadId) {
- setThreadId(message.threadId);
+ fetch: async (url, options) => {
+ const response = await fetch(url, options);
+ const tempThreadId = response.headers.get('x-thread-id');
+ if (tempThreadId) {
+ setThreadId(tempThreadId);
}
+ return response;
},
+ streamProtocol: 'data',
+ sendExtraMessageFields: true,
});
return (
@@ -120,29 +125,42 @@ export function AssistantWidget({ domain }) {
: 'bg-gray-100 text-gray-900'
}`}
>
-
+
{message.content}
- {/* Display sources if available */}
- {message.sources && message.sources.length > 0 && (
-
@@ -248,31 +266,27 @@ Check the following to confirm the widget is working:
### Filter by documentation section
-Limit the assistant's responses to specific sections of your documentation by adding a `filter` parameter to the request body. For example, to only search the API reference section, add `filter: '/api-reference'`.
+Limit the assistant's responses to specific sections of your documentation by adding a `filter` parameter to the request body:
```jsx
-const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
- api: `https://api.mintlify.com/v1/assistant/${domain}/message`,
- headers: {
- 'Authorization': `Bearer ${process.env.REACT_APP_MINTLIFY_TOKEN}`,
- },
- body: {
- threadId: threadId,
- filter: '/api-reference', // Only search API reference section
- },
- // ... rest of config
-});
+body: {
+ fp: userId,
+ threadId: threadId,
+ filter: {
+ path: '/api-reference' // Only search the API reference section
+ }
+},
```
### Track user sessions
-Pass a user identifier to track sessions and provide personalized assistance.
+The `fp` (fingerprint) parameter is already included in the component to track user sessions. You can pass a unique user identifier to provide personalized assistance and analytics:
```jsx
-body: {
- threadId: threadId,
- fp: userId, // User fingerprint or ID
-},
+
```
### Customize styling
@@ -302,6 +316,7 @@ The component uses Tailwind CSS classes. Customize the appearance by modifying t
### Thread context not maintained
-- Verify the `threadId` is being stored and passed correctly.
-- Check that the `onFinish` callback is setting the thread ID from the response.
+- Verify the `threadId` is being extracted from the `x-thread-id` response header.
+- Check that the custom `fetch` function is implemented correctly.
- Ensure the `threadId` state persists between messages.
+- Confirm `streamProtocol: 'data'` is set in the useChat configuration.
From 47c11cd8a9273562bc97f8024d5c9f1d7b475fcc Mon Sep 17 00:00:00 2001
From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com>
Date: Mon, 20 Oct 2025 13:29:34 -0700
Subject: [PATCH 06/36] add content to deflection guide
---
guides/assistant-support-deflection.mdx | 303 ++++++++++++++++++++++++
1 file changed, 303 insertions(+)
diff --git a/guides/assistant-support-deflection.mdx b/guides/assistant-support-deflection.mdx
index 01d0cdcb4..052d6b127 100644
--- a/guides/assistant-support-deflection.mdx
+++ b/guides/assistant-support-deflection.mdx
@@ -6,10 +6,313 @@ description: "Reduce support burden by auto-populating tickets with assistant co
## What you will build
+An integration that captures assistant conversations when users need additional help and automatically creates support tickets with full context. The workflow:
+
+1. User interacts with the assistant on your documentation site
+2. When the assistant can't fully answer their question, user clicks a "Contact Support" link
+3. A support ticket is automatically created with:
+ - User's original questions
+ - Assistant's responses
+ - Links to relevant documentation
+ - Conversation thread ID for reference
+
+This reduces support burden by giving your team full context before they respond, and helps identify documentation gaps.
+
## Prerequisites
+- Mintlify Pro or Custom plan
+- Support platform account (this guide uses Zendesk as an example, but the approach works for any platform)
+- Support platform API credentials
+- Basic knowledge of your support platform's API
+
+### Get your support platform API credentials
+
+**For Zendesk:**
+1. Navigate to Admin Center → Apps and integrations → APIs → Zendesk API
+2. Enable token access
+3. Click the **Add API token** button
+4. Copy and save the token securely
+5. Note your Zendesk subdomain (e.g., `yourcompany.zendesk.com`)
+
+For other platforms (Intercom, Freshdesk, etc.), consult their API documentation for authentication setup.
+
+## Understand the assistant data
+
+The Mintlify assistant provides several ways to access conversation data:
+
+### Dashboard export
+Export conversation history as CSV from your [assistant dashboard](https://dashboard.mintlify.com/products/assistant). The export includes:
+- User queries
+- Assistant responses
+- Source citations
+- Timestamps
+- Thread IDs
+
+### Built-in deflection
+Configure a deflection email in your [assistant settings](https://dashboard.mintlify.com/products/assistant/settings). When the assistant cannot answer a question, it displays this email to users.
+
+### Custom integration
+For programmatic access, you can build a custom contact form that captures the current conversation state and sends it to your support system.
+
## Build the integration
+This guide shows how to build a serverless function that creates support tickets from assistant conversation data.
+
+### Create a contact support page
+
+Add a dedicated contact page to your documentation that captures assistant context when users need help.
+
+Create `contact-support.mdx` in your docs:
+
+```mdx contact-support.mdx
+---
+title: "Contact Support"
+description: "Get help from our support team"
+---
+
+If the assistant couldn't answer your question, our support team is here to help.
+
+
+
+
+```
+
+### Create the ticket creation endpoint
+
+Create a serverless function to handle ticket creation. This example uses Vercel, but you can adapt it for any platform.
+
+Create `api/create-ticket.js`:
+
+```javascript api/create-ticket.js
+export default async function handler(req, res) {
+ if (req.method !== 'POST') {
+ return res.status(405).json({ error: 'Method not allowed' });
+ }
+
+ const { email, subject, description, conversation_context } = req.body;
+
+ // Parse conversation context if provided
+ let contextNote = '';
+ if (conversation_context) {
+ try {
+ const context = JSON.parse(conversation_context);
+ contextNote = formatConversationContext(context);
+ } catch (e) {
+ console.error('Failed to parse conversation context:', e);
+ }
+ }
+
+ // Create Zendesk ticket
+ const ticketData = {
+ ticket: {
+ subject: subject,
+ comment: {
+ body: `${description}\n\n---\n\nAssistant Conversation History:\n${contextNote}`
+ },
+ requester: {
+ email: email,
+ name: email.split('@')[0]
+ },
+ priority: 'normal',
+ tags: ['assistant_escalation']
+ }
+ };
+
+ try {
+ const response = await fetch(
+ `https://${process.env.ZENDESK_SUBDOMAIN}.zendesk.com/api/v2/tickets.json`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': `Basic ${Buffer.from(
+ `${process.env.ZENDESK_EMAIL}/token:${process.env.ZENDESK_API_TOKEN}`
+ ).toString('base64')}`
+ },
+ body: JSON.stringify(ticketData)
+ }
+ );
+
+ if (!response.ok) {
+ throw new Error(`Zendesk API error: ${response.status}`);
+ }
+
+ const result = await response.json();
+
+ return res.status(200).json({
+ success: true,
+ ticket_id: result.ticket.id,
+ ticket_url: `https://${process.env.ZENDESK_SUBDOMAIN}.zendesk.com/agent/tickets/${result.ticket.id}`
+ });
+
+ } catch (error) {
+ console.error('Error creating ticket:', error);
+ return res.status(500).json({
+ error: 'Failed to create support ticket',
+ message: error.message
+ });
+ }
+}
+
+function formatConversationContext(context) {
+ if (!context.messages || context.messages.length === 0) {
+ return 'No conversation history available.';
+ }
+
+ return context.messages
+ .map((msg, index) => {
+ const role = msg.role === 'user' ? 'User' : 'Assistant';
+ const sources = msg.sources
+ ? `\nSources: ${msg.sources.map(s => s.url).join(', ')}`
+ : '';
+
+ return `${index + 1}. ${role}: ${msg.content}${sources}`;
+ })
+ .join('\n\n');
+}
+```
+
+### Configure environment variables
+
+Add your support platform credentials to your environment:
+
+```bash .env
+ZENDESK_SUBDOMAIN=yourcompany
+ZENDESK_EMAIL=support@yourcompany.com
+ZENDESK_API_TOKEN=your_api_token_here
+```
+
+For Vercel, add these in your project settings under Environment Variables.
+
+### Link from the assistant
+
+Update your assistant configuration to direct users to your contact page:
+
+1. Navigate to your [assistant settings](https://dashboard.mintlify.com/products/assistant/settings)
+2. In the deflection email section, you can include a link to your contact page: "Visit [our support page](https://docs.yourcompany.com/contact-support) for help"
+
## Test the integration
+1. Navigate to your documentation site
+2. Open the assistant and ask a question it might not fully answer
+3. Click the contact support link
+4. Fill out the form and submit
+5. Verify the ticket was created in your support system
+
+### Verify the integration
+
+Check the following to confirm the workflow is working:
+
+- Ticket appears in your support platform (Zendesk, etc.)
+- Ticket includes the user's description
+- Ticket includes formatted conversation context from the assistant
+- Ticket is tagged appropriately for tracking
+- Support team can access all relevant information
+
+## Optional enhancements
+
+### Add user identification
+
+If users are authenticated on your docs site, include their user ID for better tracking:
+
+```javascript
+const ticketData = {
+ ticket: {
+ subject: subject,
+ comment: { body: description },
+ requester: {
+ email: email,
+ name: req.body.user_name || email.split('@')[0]
+ },
+ custom_fields: [
+ { id: 'user_id_field_id', value: req.body.user_id }
+ ],
+ tags: ['assistant_escalation', 'authenticated_user']
+ }
+};
+```
+
+### Analyze deflection patterns
+
+Use the assistant dashboard to export conversation data and analyze:
+- What questions lead to support tickets?
+- Which documentation pages are most frequently cited before escalation?
+- What topics have low deflection rates (need better docs)?
+
+Export data from your [assistant dashboard](https://dashboard.mintlify.com/products/assistant) and analyze with your preferred tool.
+
+### Integrate with multiple platforms
+
+Adapt the serverless function to support multiple platforms based on configuration:
+
+```javascript
+const PLATFORM_HANDLERS = {
+ zendesk: createZendeskTicket,
+ intercom: createIntercomConversation,
+ freshdesk: createFreshdeskTicket
+};
+
+const platform = process.env.SUPPORT_PLATFORM || 'zendesk';
+const handler = PLATFORM_HANDLERS[platform];
+
+if (!handler) {
+ throw new Error(`Unsupported platform: ${platform}`);
+}
+
+await handler(ticketData);
+```
+
## Troubleshooting
+
+### Tickets not being created
+
+- Verify your API credentials are correct and have proper permissions
+- Check that your support platform API is accessible from your serverless function
+- Review serverless function logs for error messages
+- Test API credentials with a simple curl command:
+ ```bash
+ curl https://yourcompany.zendesk.com/api/v2/tickets.json \
+ -u email/token:api_token \
+ -X GET
+ ```
+
+### Conversation context is empty
+
+- Verify the assistant conversation is being stored in localStorage
+- Check browser console for JavaScript errors
+- Ensure the contact form is properly capturing the hidden field value
+- Test with a fresh conversation in the assistant
+
+### Tickets missing information
+
+- Check the `formatConversationContext` function is parsing data correctly
+- Verify the conversation context JSON structure matches your expectations
+- Add console logging to debug the data being sent
+- Review the support platform's field requirements
+
+### Authentication errors
+
+- Confirm your API token hasn't expired
+- Verify the subdomain is correct (no `https://` prefix)
+- Check that email/token format matches platform requirements (e.g., `email/token:api_token` for Zendesk)
+- Ensure API token has permission to create tickets
From f1fcda8c289e879de6650e36c7dd2536a4e7a2ae Mon Sep 17 00:00:00 2001
From: Ethan Palm <56270045+ethanpalm@users.noreply.github.com>
Date: Tue, 21 Oct 2025 10:57:16 -0700
Subject: [PATCH 07/36] Update assistant-widget.mdx
---
guides/assistant-widget.mdx | 275 +++++++++++++++++++++++++++++++-----
1 file changed, 242 insertions(+), 33 deletions(-)
diff --git a/guides/assistant-widget.mdx b/guides/assistant-widget.mdx
index cc32d18f4..f7b958a7b 100644
--- a/guides/assistant-widget.mdx
+++ b/guides/assistant-widget.mdx
@@ -19,7 +19,7 @@ This allows users to get help with your product without leaving your application
## Prerequisites
- Mintlify Pro or Custom plan
-- Your documentation domain (for example, `docs.yourcompany.com`)
+- Your Mintlify project identifier (found in your [dashboard](https://dashboard.mintlify.com))
- Node.js and npm installed
- Basic React knowledge
- Existing React application (Next.js, Vite, Create React App, etc.)
@@ -38,10 +38,10 @@ This allows users to get help with your product without leaving your application
### Install dependencies
-Install the AI SDK for React and Mintlify's assistant integration:
+Install the AI SDK for React and a Markdown renderer:
```bash
-npm install ai @ai-sdk/react
+npm install ai @ai-sdk/react react-markdown
```
### Create the assistant component
@@ -50,20 +50,37 @@ Create a new file `AssistantWidget.jsx` (or `.tsx` if using TypeScript) in your
```jsx AssistantWidget.jsx expandable
import { useChat } from '@ai-sdk/react';
-import { useState } from 'react';
-
-export function AssistantWidget({ domain, userId = 'anonymous' }) {
+import { useState, useRef, useEffect } from 'react';
+import ReactMarkdown from 'react-markdown';
+
+export function AssistantWidget({
+ domain,
+ userId = 'anonymous',
+ // Customization props
+ buttonColor = '#2563eb', // blue-600
+ accentColor = '#2563eb',
+ position = 'bottom-right',
+ headerTitle = 'Documentation Assistant',
+ headerSubtitle = 'Ask me anything about our docs',
+ emptyStateText = 'How can I help you today?',
+ inputPlaceholder = 'Ask a question...',
+ sendButtonText = 'Send',
+}) {
const [isOpen, setIsOpen] = useState(false);
const [threadId, setThreadId] = useState(null);
+ const messagesEndRef = useRef(null);
+ const closeButtonRef = useRef(null);
const { messages, input, handleInputChange, handleSubmit, isLoading } = useChat({
- api: `https://api.mintlify.com/v1/assistant/${domain}/message`,
+ api: `https://api-dsc.mintlify.com/v1/assistant/${domain}/message`,
headers: {
'Authorization': `Bearer ${process.env.REACT_APP_MINTLIFY_TOKEN}`,
},
body: {
fp: userId,
threadId: threadId,
+ retrievalPageSize: 5,
+ filter: null,
},
fetch: async (url, options) => {
const response = await fetch(url, options);
@@ -77,13 +94,63 @@ export function AssistantWidget({ domain, userId = 'anonymous' }) {
sendExtraMessageFields: true,
});
+ // Scroll to latest message
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
+ }, [messages]);
+
+ // Handle keyboard shortcuts (Escape to close)
+ useEffect(() => {
+ const handleKeyDown = (e) => {
+ if (e.key === 'Escape' && isOpen) {
+ setIsOpen(false);
+ }
+ };
+ if (isOpen) {
+ document.addEventListener('keydown', handleKeyDown);
+ return () => document.removeEventListener('keydown', handleKeyDown);
+ }
+ }, [isOpen]);
+
+ // Focus management when opening
+ useEffect(() => {
+ if (isOpen && closeButtonRef.current) {
+ closeButtonRef.current.focus();
+ }
+ }, [isOpen]);
+
+ // Helper function to convert hex to rgb
+ const hexToRgb = (hex) => {
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+ return result ? `${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt(result[3], 16)}` : '37, 99, 235';
+ };
+
+ const getPositionClasses = () => {
+ const positions = {
+ 'bottom-right': 'bottom-4 right-4',
+ 'bottom-left': 'bottom-4 left-4',
+ 'top-right': 'top-4 right-4',
+ 'top-left': 'top-4 left-4',
+ };
+ return positions[position] || positions['bottom-right'];
+ };
+
+ const panelPosition = {
+ 'bottom-right': 'bottom-20 right-4',
+ 'bottom-left': 'bottom-20 left-4',
+ 'top-right': 'top-20 right-4',
+ 'top-left': 'top-20 left-4',
+ };
+
return (
<>
{/* Toggle button */}