Skip to main content

HoopAI AI Chat Widget — Design Spec

Date: 2026-03-29 Status: Approved

Problem

The current VoiceGlow/ConvoCore widget is broken and unreliable. It is a third-party hosted service with no control over uptime, UI, or AI behaviour. API keys cannot be managed securely and the UI does not match the HoopAI design system.

Goal

Replace VoiceGlow entirely with a fully custom AI chat widget powered by Claude Haiku 4.5 via OpenRouter, backed by a Cloudflare Worker proxy that keeps all API keys off the client. The widget should match Mintlify’s native AI panel UX — a right-side drawer that pushes page content left — and feel like a first-class part of the docs site.

Architecture

Browser (help.hoopai.com — static Mintlify)
  theme/chat-widget.js

      │  POST /chat  (SSE stream)

  Cloudflare Worker  (hoopai-chat-api.workers.dev)
      │  env: OPENROUTER_API_KEY  (secret, never in code)
      │  env: BRAVE_SEARCH_API_KEY  (secret, optional)

      ├──▶  OpenRouter → anthropic/claude-haiku-4-5  (streaming)
      └──▶  Brave Search API  (web search tool)

Why Cloudflare Workers

  • Edge-deployed, ~0ms cold start, global low latency
  • Free tier: 100k requests/day — more than sufficient for a help centre
  • Secrets stored in Cloudflare dashboard, never in git or code
  • Streaming SSE supported natively
  • No separate server to maintain

Part 1 — Cloudflare Worker

Location: worker/ directory in the repo (Mintlify ignores this)

Files

worker/
  wrangler.toml     — worker config (name, compat date, vars)
  src/index.js      — worker entry point

Endpoint: POST /chat

Request body:
{
  "messages": [{ "role": "user", "content": "..." }],
  "pageContext": { "title": "...", "url": "..." }
}
Response: text/event-stream (SSE), OpenRouter streaming format passed through directly.

Tools the AI can call

ToolDescriptionImplementation
web_searchSearch the web for current infoCalls Brave Search API from the Worker
create_support_ticketCreate a support ticketSends structured payload to a configurable webhook URL

Security

  • CORS: Access-Control-Allow-Origin locked to https://help.hoopai.com and http://localhost:3000
  • No other origin can call the worker
  • OPENROUTER_API_KEY set via wrangler secret put — never in code
  • Rate limiting: Cloudflare’s default per-IP rate limiting applies

System prompt (injected by worker)

You are a helpful support assistant for HoopAI — an all-in-one CRM and marketing platform.
You are embedded in the HoopAI Help Center documentation site.
Current page: {pageContext.title} ({pageContext.url})

Answer questions about HoopAI features directly and concisely.
When the user asks about something not covered in your training, use web_search to find current information.
When a user has an unresolved issue that needs human support, offer to create a support ticket using create_support_ticket.
Never mention GoHighLevel, HighLevel, GHL, Marketing Muse, or WhoPayI — always say "HoopAI" or "Hoop".

Part 2 — Custom Chat Widget

Location: theme/chat-widget.js (replaces current VoiceGlow file entirely) CSS: New #hoopai-panel-* rules added to theme/custom.css

Panel Behaviour

  • Fixed right-side drawer, position: fixed, top: 0, right: 0, height: 100vh
  • Default width: 380px. Expanded width: 680px. Both transition smoothly.
  • When open: body.hoopai-panel-open #content-side-layout { margin-right: 380px } — content pushes left
  • When expanded: margin increases to 680px
  • Transition: 0.25s ease on both the panel and the content margin
  • Z-index: high enough to sit above Mintlify’s sidebar overlay but below modals
  • Inherits dark/light mode automatically via existing --ds-* CSS custom properties

Panel Structure (HTML)

#hoopai-panel
  #hoopai-panel-header
    .hoopai-panel-logo    (sparkle icon)
    .hoopai-panel-title   ("Ask AI")
    .hoopai-panel-actions
      #hoopai-expand-btn  (expand/collapse)
      #hoopai-clear-btn   (clear conversation)
      #hoopai-close-btn   (close panel)
  #hoopai-panel-messages
    .hoopai-msg-empty     (shown when no messages — suggested prompts)
    .hoopai-msg-user      (user message bubble)
    .hoopai-msg-assistant (assistant bubble, streams in token by token)
    .hoopai-msg-tool      (tool call pill: "Searching the web…")
  #hoopai-panel-footer
    #hoopai-input         (textarea, auto-grows)
    #hoopai-send-btn      (send, disabled while streaming)

Suggested prompts (empty state)

Three prompts generated from the current page title shown as clickable chips. Clicking one fills the input and sends.

Streaming

  • Uses fetch with ReadableStream to consume the SSE from the Worker
  • Renders tokens progressively into the assistant bubble as they arrive
  • Shows an animated three-dot indicator while waiting for first token
  • Send button disabled + shows stop icon during streaming; clicking it aborts the stream

Tool call display

When the AI calls web_search or create_support_ticket, a pill appears in the message list:
  • 🔍 Searching the web… → replaced with 🔍 Web search complete when done
  • 🎫 Creating support ticket… → replaced with ✓ Ticket created when done

Page context injection

Every new conversation automatically prepends page context. When triggered from:
  • Navbar / page Ask AI button — context message shown as a small pill above the input: 📄 Reading: <page title>
  • Code block Ask AI button — code snippet shown in a collapsed expandable above the input

Ask AI entry points (all preserved from current widget)

  1. Navbar button (desktop) — #assistant-entry
  2. Mobile header button — #assistant-entry-mobile
  3. Code block button — data-ask-ai-injected
  4. Page-level button — #page-ask-ai-btn
  5. Keyboard shortcut — Ctrl+I / Cmd+I

Dark / light mode

All colours use var(--ds-*) tokens from theme/custom.css. No hardcoded colours in widget JS or CSS. Panel automatically matches the site theme.

Part 3 — Deployment Steps

  1. Install Wrangler CLI locally: npm install -g wrangler
  2. Authenticate: CLOUDFLARE_API_TOKEN=<token> wrangler whoami
  3. Deploy worker: CLOUDFLARE_API_TOKEN=<token> wrangler deploy
  4. Set secrets:
    wrangler secret put OPENROUTER_API_KEY
    wrangler secret put BRAVE_SEARCH_API_KEY   (optional, enables web search)
    
  5. Capture deployed Worker URL (https://hoopai-chat-api.<account>.workers.dev)
  6. Embed Worker URL in theme/chat-widget.js as WORKER_URL constant
  7. Remove VoiceGlow script and window.VG_CONFIG from widget JS

Out of Scope (this phase)

  • Custom domain for the Worker (can be added later in Cloudflare dashboard)
  • Conversation persistence across page loads (each page load starts fresh)
  • User authentication / per-user history
  • HoopAI CRM integration for ticket creation (webhook URL to be provided by user)
  • Brave Search setup (slot wired, key optional — web search gracefully disabled if key absent)
Last modified on April 16, 2026