@mnexium/chat
v2.2.1
Published
Drop-in chat widget with AI memory powered by Mnexium - works with React, Express, or vanilla JS
Maintainers
Readme
@mnexium/chat
A drop-in chat widget that gives any web app a full AI chat experience backed by Mnexium. Works with React, Express, or vanilla JavaScript.

Features
- Framework Flexible - React component, Express middleware, or vanilla JS client
- Floating Widget - Modern glassmorphism design with smooth animations
- Persistent Memory - Conversations and user context persist across sessions
- Streaming Responses - Real-time streaming with typing effect
- Multi-Provider Support - Works with OpenAI, Anthropic Claude, and Google Gemini
- Markdown Rendering - Rich formatting for assistant messages
- Zero Client-Side Keys - All API keys stay on your server
- Theming - Light and dark themes with customizable primary color
- Mobile Optimized - Full-screen chat on mobile with body scroll lock
Installation
npm install @mnexium/chatPackage Exports
| Import | Description |
|--------|-------------|
| @mnexium/chat | React component with full UI |
| @mnexium/chat/browser | Browser bundle (script tag, no build required) |
| @mnexium/chat/core | Vanilla JS client (framework-agnostic) |
| @mnexium/chat/server | Server handlers (Next.js + Express) |
Quick Start (React + Next.js)
1. Add the Chat Widget
import { MnexiumChat } from '@mnexium/chat';
export default function Layout({ children }) {
return (
<>
{children}
<MnexiumChat endpoint="/api/mnx" />
</>
);
}This adds a floating "Ask AI" button to the bottom-right of your page.
2. Set Up Server Routes
app/api/mnx/_mnx.ts
import { createHandlers } from '@mnexium/chat/server';
export const mnx = createHandlers({
model: process.env.MODEL ?? 'gpt-4o-mini',
cookiePrefix: 'mnx',
mnxOptions: {
history: true,
learn: true,
recall: true,
profile: true,
summarize: 'balanced',
},
});app/api/mnx/bootstrap/route.ts
import { mnx } from '../_mnx';
export const GET = mnx.bootstrap;app/api/mnx/chat/route.ts
import { mnx } from '../_mnx';
export const POST = mnx.chat;app/api/mnx/new-chat/route.ts
import { mnx } from '../_mnx';
export const POST = mnx.newChat;app/api/mnx/conversations/[chatId]/route.ts
import { mnx } from '../../_mnx';
export async function GET(
req: Request,
{ params }: { params: { chatId: string } }
) {
return mnx.conversation(req, params.chatId);
}3. Configure Environment Variables
# .env.local
MNX_API_KEY=mnx_live_...
# Include one or all of the following provider keys:
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_API_KEY=...
# Optionally set the model (defaults to gpt-4o-mini)
# MODEL=gpt-4o-mini
# MODEL=claude-3-haiku-20240307
# MODEL=gemini-2.0-flash-litePlain HTML (No Build Required)
For non-React apps, use the browser bundle with a simple script tag. Same UI as React!
1. Set Up Express Server
import express from 'express';
import { mountMnexiumRoutes } from '@mnexium/chat/server';
const app = express();
app.use(express.json());
app.use(express.static('public'));
// Serve the browser bundle
app.get('/mnexium-chat.js', (req, res) => {
res.sendFile(require.resolve('@mnexium/chat/browser'));
});
// Mount Mnexium API routes
mountMnexiumRoutes(app, '/api/mnx');
app.listen(3000);2. Add Script Tag to HTML
<!-- Just add this script tag! -->
<script
src="/mnexium-chat.js"
data-endpoint="/api/mnx"
data-title="Ask AI"
data-button-label="Ask AI"
data-theme="dark"
data-history="true"
></script>That's it! The floating chat button appears automatically.
Script Data Attributes
| Attribute | Description |
|-----------|-------------|
| data-endpoint | API endpoint (default: /api/mnx) |
| data-title | Chat window title |
| data-button-label | Floating button label |
| data-position | bottom-right or bottom-left |
| data-primary-color | Accent color (hex) |
| data-text-color | Button text color |
| data-theme | light or dark |
| data-logo | Logo image URL |
| data-welcome-icon | Welcome emoji |
| data-welcome-message | Welcome text |
| data-default-open | true to start open |
| data-history | true to load history |
| data-eager-init | false to delay init |
Programmatic Usage
<script src="/mnexium-chat.js" data-auto-init="false"></script>
<script>
// Render manually with options
MnexiumChat.render({
endpoint: '/api/mnx',
title: 'Support',
primaryColor: '#45b1eb',
theme: 'dark',
});
</script>Vanilla JS Client (Build Your Own UI)
For custom UIs, use the core client directly:
import { MnexiumClient } from '@mnexium/chat/core';
const chat = new MnexiumClient({ endpoint: '/api/mnx', history: true });
chat.onMessage((messages) => renderMessages(messages));
chat.onStateChange((state) => updateUI(state));
await chat.init();
await chat.send('Hello!');Component Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| endpoint | string | '/api/mnx' | Base URL for API routes |
| title | string | 'Ask AI' | Chat window header title |
| buttonLabel | string | 'Ask AI' | Floating button label |
| placeholder | string | 'Type a message...' | Input placeholder |
| position | 'bottom-right' \| 'bottom-left' | 'bottom-right' | Widget position |
| primaryColor | string | '#facc15' | Accent color (use 6-char hex, e.g. #45b1eb) |
| textColor | string | '#000' | Text color for button and user messages |
| theme | 'light' \| 'dark' | 'dark' | Color theme |
| defaultOpen | boolean | false | Start with chat open |
| eagerInit | boolean | true | Initialize on page load (no "Initializing..." delay) |
| logo | string | - | URL to custom logo image |
| welcomeIcon | string | '👋' | Emoji shown in empty chat |
| welcomeMessage | string | 'How can I help you today?' | Welcome message |
| history | boolean | false | Load previous conversation on open |
Server Handler Options
createHandlers(config) (Recommended)
Creates all handlers with shared configuration:
const mnx = createHandlers({
model: 'gpt-4o-mini',
cookiePrefix: 'mnx',
chatPrefix: '_landing', // Optional: creates separate chat sessions
mnxOptions: { ... },
});
// Returns: { bootstrap, chat, newChat, history, conversation }| Option | Type | Default | Description |
|--------|------|---------|-------------|
| model | string | 'gpt-4o-mini' | LLM model to use |
| cookiePrefix | string | 'mnx' | Prefix for session cookies |
| chatPrefix | string | - | Optional suffix appended to cookiePrefix for the chat cookie (e.g., cookiePrefix: 'mnx' + chatPrefix: '_landing' → cookie name mnx_landing_chat) |
| mnxOptions.history | boolean | true | Enable conversation history |
| mnxOptions.learn | boolean \| 'force' | true | Extract and store memories |
| mnxOptions.recall | boolean | true | Inject relevant memories |
| mnxOptions.profile | boolean | true | Include user profile |
| mnxOptions.summarize | 'light' \| 'balanced' \| 'aggressive' \| false | 'balanced' | Summarization mode |
| mnxOptions.system_prompt | string | - | System prompt text for the AI assistant |
Individual Handlers
You can also import handlers individually:
import { bootstrapHandler, chatHandler, newChatHandler, historyHandler, conversationHandler } from '@mnexium/chat/server';Express Middleware
For Express apps, use createExpressMiddleware or mountMnexiumRoutes:
import { createExpressMiddleware, mountMnexiumRoutes } from '@mnexium/chat/server';
// Option 1: Mount all routes at once
mountMnexiumRoutes(app, '/api/mnx');
// Option 2: Use individual middleware handlers
const mnx = createExpressMiddleware({ cookiePrefix: 'mnx' });
app.get('/api/mnx/bootstrap', mnx.bootstrap);
app.post('/api/mnx/chat', mnx.chat);
app.post('/api/mnx/new-chat', mnx.newChat);
app.get('/api/mnx/conversations/:chatId', mnx.conversation);Supported Models
OpenAI: gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-4, gpt-3.5-turbo, o1, o1-mini
Anthropic: claude-3-opus, claude-3-sonnet, claude-3-haiku, claude-3-5-sonnet, claude-sonnet-4
Google Gemini: gemini-2.0-flash-lite, gemini-2.5-flash, gemini-1.5-pro, gemini-1.5-flash
How It Works
- On mount, the client calls
GET /api/mnx/bootstrap - Server generates or retrieves
subject_idandchat_idfrom cookies - If a previous chat exists, it's loaded from Mnexium history
- On send, the client
POSTs to/api/mnx/chat - Server forwards to Mnexium with memory/history flags
- Response streams back to client in real-time
All API keys remain server-side. The client never sees or constructs Mnexium requests.
Full Next.js Example
app/
├── api/
│ └── mnx/
│ ├── _mnx.ts # Shared config
│ ├── bootstrap/
│ │ └── route.ts
│ ├── chat/
│ │ └── route.ts
│ ├── new-chat/
│ │ └── route.ts
│ └── conversations/
│ └── [chatId]/
│ └── route.ts
└── layout.tsxapp/layout.tsx
import { MnexiumChat } from '@mnexium/chat';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<MnexiumChat
endpoint="/api/mnx"
title="Ask AI"
buttonLabel="Ask AI"
position="bottom-right"
primaryColor="#45b1eb"
textColor="#fff"
theme="dark"
logo="/logo.png"
welcomeIcon="🤖"
welcomeMessage="Ask me anything!"
history={true}
/>
</body>
</html>
);
}Full Express Example
project/
├── server.js
├── public/
│ └── index.html
├── package.json
└── .envserver.js
import 'dotenv/config';
import express from 'express';
import { createRequire } from 'module';
import { mountMnexiumRoutes } from '@mnexium/chat/server';
const require = createRequire(import.meta.url);
const app = express();
app.use(express.json());
app.use(express.static('public'));
// Serve the browser bundle
app.get('/mnexium-chat.js', (req, res) => {
res.sendFile(require.resolve('@mnexium/chat/browser'));
});
// Mount API routes
mountMnexiumRoutes(app, '/api/mnx');
app.listen(3000, () => console.log('Server running on http://localhost:3000'));public/index.html
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
<h1>Welcome</h1>
<!-- Mnexium Chat Widget -->
<script
src="/mnexium-chat.js"
data-endpoint="/api/mnx"
data-theme="dark"
></script>
</body>
</html>.env
MNX_API_KEY=mnx_live_...
OPENAI_API_KEY=sk-...See examples/express-demo for a complete working example.
License
MIT
