Add Pernoex to your product.
Use the widget, MCP server or API to let people ask questions and get answers from your indexed docs. Every answer can include the source it used.
Floating mode
The default setup is a chat button in the corner of your page. Add this before the closing </body> tag:
<script
src="https://cdn.pernoex.com/widget.js"
data-api-key="YOUR_API_KEY"
></script>
For self-hosted instances, add data-api-url pointing at your endpoint.
Embedded mode
Put the chat inside a container on your page. This works well for help pages, sidebars and custom layouts. The container needs a defined height.
Pernoex.init({
apiKey: 'YOUR_API_KEY',
mode: 'embedded',
container: '#chat-container',
showHeader: true,
borderRadius: '12px'
});
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | string | required | Your project's public API key |
| mode | enum | floating | floating · embedded · inline |
| container | selector | none | Required for embedded mode |
| showHeader | boolean | true | Show or hide the header in embedded mode |
| borderRadius | string | '0' | CSS radius for the container |
| showAvatars | boolean | true | Show user/bot avatars next to messages |
| theme | object | none | Color & style overrides (see Theme) |
| startPills | string[] | none | Override the empty-state suggestion pills |
Inline Explainer
Let users highlight text and ask a follow-up question. Pernoex opens a sidebar, answers from your knowledge base and keeps the original text visible. Turn it on in the dashboard or control it with selectors in code.
apiKey: 'YOUR_API_KEY',
inline: {
enabled: true,
triggerSelector: 'article, .docs-content',
excludeSelector: 'nav, .code-block',
showFollowUp: true
}
});
| Option | Type | Default | Description |
|---|---|---|---|
| enabled | boolean | false | Override the dashboard setting |
| triggerSelector | string | none | Limit where text selection triggers the explainer |
| excludeSelector | string | none | Areas to exclude from selection |
| position | enum | auto | auto · above · below |
| showFollowUp | boolean | false | Allow follow-up questions in the sidebar |
Suggestion pills
On the empty state, the widget can show three suggested questions based on the current page. A visitor on /pricing can see pricing questions. Pass startPills to set your own questions.
MCP setup (IDE)Growth+
Connect your docs to AI code editors with the Model Context Protocol. Pernoex works with VS Code, Cursor, Claude Code, JetBrains and Windsurf. Generate a developer key (dk_live_) from your project's Surface page. The default limit is 200 requests/day per IP.
{
"servers": {
"pernoex": {
"url": "https://mcp.pernoex.com/mcp",
"headers": { "Authorization": "Bearer dk_live_…" }
}
}
}
Each IDE has its own config file. The server URL and Bearer header stay the same.
| IDE | Config location | Transport |
|---|---|---|
| VS Code | .vscode/mcp.json | HTTP /mcp |
| Cursor | .cursor/mcp.json | HTTP /mcp |
| Claude Code | claude mcp add … | HTTP /mcp |
| JetBrains | Settings → MCP Servers | HTTP /mcp |
| Windsurf | ~/.codeium/windsurf/… | SSE /sse |
Sessions have a 30-minute idle timeout and reconnect automatically; each developer key supports up to 10 concurrent sessions.
MCP tools
| Tool | Key | Returns |
|---|---|---|
| pernoex_ask | dk_live_ | A written answer from your indexed docs |
| pernoex_search | sk_live_ | Ranked source passages with relevance scores, without an AI-written answer |
Theme customization
Pass a theme object with any combination of color overrides — all optional. Set background: 'transparent' for seamless embedding, or fontFamily: 'inherit'to use your page's font.
background: '#1a1a2e',
assistantBubbleBg: '#16213e',
userBubbleBg: '#0f172a',
linkColor: '#818cf8',
fontFamily: '"Inter", sans-serif'
}
| Property | Applies to |
|---|---|
| background | Messages area & window — use 'transparent' to blend in |
| assistantBubbleBg / TextColor | Assistant message bubble and text |
| userBubbleBg / TextColor | User message bubble and text |
| linkColor | Links inside messages |
| inputBg / inputBorderColor | Input field background and border |
| sendButtonBg / Color | Send button background and icon |
| fontFamily | Global font — pass 'inherit' for your page's stack |
JavaScript API
After init(), control methods are on the global Pernoex object, and lifecycle callbacks can be passed to init.
Pernoex.isOpen() · Pernoex.clearMessages()
await Pernoex.explain("text to explain")
// callbacks
{ onReady, onOpen, onClose, onMessage, onError }
- ✻Copy for AI Agent — formats the full thread (question, answer, sources) for pasting into Cursor, VS Code or Claude Code.
- ✻Per-message & code-block copy — copy any single response, or just a code block without surrounding markdown.
- ✻Image lightbox — images in source content open full-screen on click.
- ✻Host font inheritance — set
fontFamily: 'inherit'to match your page's type.
SSE events
Streamed responses connect over Server-Sent Events. For custom integrations, these are the event types you'll receive from /api/v1/chat/stream:
| Event | Payload | Description |
|---|---|---|
| session_context | object | Session metadata including conversation_id |
| tool / tool_complete | object | Custom action invoked, and its result |
| text | string | Streamed answer chunk — append to the response |
| sources | array | Source citations, each with title, URL and score |
| confidence | 0–1 | Answer confidence — below 0.5 may signal a content gap |
| done | — | Stream complete — close the connection |
REST APIScale
Query your knowledge base server-side with a secret key (sk_live_). Never expose secret keys in client-side code. Rate limit: 1,000 requests/minute.
curl -X POST https://api.pernoex.com/v1/query \
-H "Authorization: Bearer sk_live_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{ "query": "How do I set up webhooks?" }'
Use /v1/search to retrieve ranked documents without generating an answer.
Custom ActionsGrowth+
Let the AI call your APIs during a conversation. It can check an order, reset a password or look up an account across chat, Slack and voice. Auth headers are stored server-side and never exposed; every call is logged in your audit trail. Use confirmation_required: true for write operations. Growth: up to 5 per project. Scale: up to 25.
"name": "check_order_status",
"endpoint": "https://api.yourapp.com/orders/lookup",
"method": "POST",
"parameters": [{ "name": "order_id", "required": true }],
"confirmation_required": false
}
Slack
Add Pernoex to your workspace so your team or customers can tag @Pernoex in any thread and get answers from your docs, with clickable source links. The bot reads full thread context, including images, and supports DMs. On Scale, use your own Slack app with a custom name, avatar and description.
Framework examples
Load the script and call init() on mount. In React, clean up with Pernoex.destroy() on unmount.
useEffect(() => {
const s = document.createElement('script');
s.src = 'https://cdn.pernoex.com/widget.js';
s.setAttribute('data-manual-init', 'true');
s.onload = () => window.Pernoex.init({ apiKey, mode: 'embedded', container });
document.body.appendChild(s);
return () => window.Pernoex?.destroy();
}, []);
Identity verification (HMAC)Growth+
Confirm a user is who your server says they are. Compute an HMAC-SHA256of the user's details server-side and pass only the result to the widget. The identity secret must never appear in client-side code.
const payload = [userId, email, name].join(':');
const hmac = crypto.createHmac('sha256', secret)
.update(payload).digest('hex');
Webhook signingScale
Event webhooks, such as conversation completed, handoff triggered and content gap detected, are signed so you can verify they came from Pernoex. Each request carries an X-Pernoex-Signature header: t=…,v1=…, where v1 is the HMAC-SHA256 of timestamp.payload. Compare with a constant-time check.
CSP & domain restrictions
The widget renders inside a Shadow DOMboundary — your CSS can't affect it and its styles can't leak into your page. Styles inject via adoptedStyleSheets, so style-src 'unsafe-inline' is not required. You can also choose which domains may load the widget from your project settings. Unlisted origins are rejected.
script-src 'self' https://cdn.pernoex.com;
connect-src 'self' https://api.pernoex.com;
style-src 'self'; font-src 'self' data: https://fonts.gstatic.com;
Troubleshooting
| Symptom | Fix |
|---|---|
| origin_not_allowed | Add the domain (or localhost:PORT) to your allowed domains list |
| Embedded container empty | Set an explicit height; confirm the element exists before init() |
| 401 on MCP | Check the dk_live_ key and the Bearer header format |
| 429 Too Many Requests | Developer keys allow 200 req/day per IP; contact support to raise it |
| Generic explanations | Ensure the knowledge base is indexed and has sufficient credit balance |