An embeddable legal AI chat widget powered by the Vaquill API. Deploy with Docker Compose and embed on any website via a single script tag or an inline iframe.
The Vaquill Chat Widget is a self-contained frontend + backend application that:
- Provides a chat interface for legal research questions
- Proxies requests to the Vaquill API and renders structured answers with case citations, court details, excerpts, and PDF links
- Supports two embed modes: floating chatbot (Intercom-style) and inline embed
- Runs in Docker for easy deployment on any server
For Docker deployment:
- Docker 20.10+ and Docker Compose (download)
- A Vaquill API key (
vq_key_...) from app.vaquill.ai/settings/api
For local development:
- Python 3.10+
- Node.js 18+
- Yarn (
npm install -g yarn) - A Vaquill API key
# 1. Copy and fill in the environment file
cp .env.example .env
# Edit .env and set VAQUILL_API_KEY=vq_key_...
# 2. Start the widget
docker-compose up -d
# 3. Open the widget in your browser
open http://localhost:8000Backend (Python 3.10+):
cd backend
pip install -r requirements.txt
VAQUILL_API_KEY=vq_key_... uvicorn main:app --reload --port 8000Backend available at http://localhost:8000.
Frontend (Node 18+):
cd frontend
yarn install
yarn dev # proxies /api to http://localhost:8000Frontend available at http://localhost:5173.
Development commands:
| Command | Description |
|---|---|
uvicorn main:app --reload |
Backend with hot reload |
yarn dev |
Frontend dev server with hot reload |
yarn build |
Production frontend build |
yarn lint |
Run ESLint |
yarn preview |
Preview production build |
All configuration is via environment variables (.env file):
| Variable | Required | Default | Description |
|---|---|---|---|
VAQUILL_API_KEY |
Yes | -- | Your Vaquill API key (vq_key_...) |
VAQUILL_API_URL |
No | https://api.vaquill.ai/api/v1 |
Vaquill API base URL |
WIDGET_MODE |
No | standard |
Default RAG mode: standard or deep |
WIDGET_TITLE |
No | Vaquill Legal AI |
Title shown in the chat header |
HOST_PORT |
No | 8000 |
Host port the container is exposed on |
ALLOWED_ORIGINS |
No | * |
CORS origins (comma-separated or *) |
VAQUILL_API_KEY=vq_key_your_key_here
VAQUILL_API_URL=https://api.vaquill.ai/api/v1
WIDGET_MODE=standard
WIDGET_TITLE=Vaquill Legal AI
HOST_PORT=8000
ALLOWED_ORIGINS=*# Start
docker-compose up -d
# Stop
docker-compose down
# View logs
docker-compose logs -fserver {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}# Install certbot
sudo apt install certbot python3-certbot-nginx
# Get certificate
sudo certbot --nginx -d yourdomain.com
# Verify auto-renewal
sudo certbot renew --dry-runBy default, ALLOWED_ORIGINS=* allows requests from any domain. For production, restrict to your website's domain:
ALLOWED_ORIGINS=https://yourdomain.com,https://www.yourdomain.comAdd one script tag before </body>:
<script
src="https://your-widget-host/embed/script-floating-chatbot.js"
data-api-url="https://your-widget-host"
data-primary-color="#1a56db"
></script>A floating button appears in the bottom-right corner. Clicking it opens a slide-in chat panel.
Script attributes:
| Attribute | Default | Description |
|---|---|---|
data-api-url |
http://localhost:8000 |
Widget backend URL |
data-primary-color |
#1a56db |
Brand accent colour |
data-button-size |
60px |
Floating button diameter |
data-chat-width |
400px |
Panel width on desktop |
data-chat-height |
600px |
Panel height |
<!-- Place this div where you want the chat -->
<div id="vaquill-widget-embed"></div>
<!-- Then include the script -->
<script
src="https://your-widget-host/embed/script-inline-embed.js"
data-api-url="https://your-widget-host"
data-height="640px"
></script>WordPress:
- Install the "Insert Headers and Footers" plugin
- Paste the script tag in the footer section
- Save and clear cache
Shopify:
- Go to Online Store > Themes > Edit Code
- Open
theme.liquid - Add the script tag before
</body> - Save
Wix:
- Add a "Custom Code" element
- Paste the script tag
- Position the element on your page
Next.js / React:
import { useEffect } from 'react';
export default function MyApp() {
useEffect(() => {
const script = document.createElement('script');
script.src = `${process.env.NEXT_PUBLIC_WIDGET_URL}/embed/script-floating-chatbot.js`;
script.setAttribute('data-api-url', process.env.NEXT_PUBLIC_WIDGET_URL);
script.defer = true;
document.body.appendChild(script);
return () => document.body.removeChild(script);
}, []);
return <YourApp />;
}See the examples/ directory for complete integration examples:
- Floating Widget Example -- floating chatbot interface
- Inline Embed Example -- inline page embedding
The backend exposes the following HTTP endpoints:
Send a message and receive an answer with legal sources.
Request body:
{
"message": "What is Section 302 of the IPC?",
"chatHistory": [
{ "role": "user", "content": "Tell me about IPC." },
{ "role": "assistant", "content": "The Indian Penal Code..." }
],
"mode": "standard"
}Response:
{
"answer": "Section 302 of the IPC prescribes...",
"sources": [
{
"caseName": "State of Maharashtra v. Prakash",
"citation": "2023 SCC 412",
"court": "Supreme Court of India",
"excerpt": "...relevant excerpt...",
"pdfUrl": "https://...",
"relevanceScore": 0.94
}
],
"questionInterpreted": "What is the punishment for murder under IPC?",
"mode": "standard",
"processingTimeMs": 1240
}Returns widget display configuration (title, branding, suggested questions).
Returns {"status": "ok"} -- used by Docker health checks.
widget/
docker-compose.yml
.env.example
backend/
Dockerfile
requirements.txt
main.py # FastAPI app, static serving
vaquill_client.py # Async Vaquill API client
markdown_processor.py # LLM markdown fixups
routes/
chat.py # POST /api/chat
frontend/
index.html
package.json
vite.config.ts
src/
App.tsx
main.tsx
index.css
components/
ChatContainer.tsx
ChatContainer.css
hooks/
useWidgetInfo.ts
types/
index.ts
utils/
api.ts
markdownPreprocessor.ts
examples/
embed-scripts/
script-floating-chatbot.js
script-inline-embed.js
test-pages/
test-floating-chatbot.html
test-inline-embed.html
- Cause: Container is not running or port is misconfigured.
- Fix: Run
docker-compose psto verify the container is up. CheckHOST_PORTin.envmatches the port you are visiting.
- Cause: The
data-api-urlin the embed script does not match the widget backend URL, orALLOWED_ORIGINSis too restrictive. - Fix: Ensure
data-api-urlpoints to your deployed widget backend. For testing, setALLOWED_ORIGINS=*.
- Cause: The query did not match any indexed legal documents, or the API key is invalid.
- Fix: Try a more specific legal query. Verify the API key at app.vaquill.ai/settings/api.
- Cause: Platform mismatch or insufficient disk space.
- Fix: On ARM64 Macs, ensure Docker Desktop supports ARM. Check disk space with
df -h.
- Cause: Backend cannot reach the Vaquill API.
- Fix: Test connectivity:
curl https://api.vaquill.ai/api/v1/health. VerifyVAQUILL_API_KEYandVAQUILL_API_URLin.env.
Vaquill provides legal information, not legal advice. Users should consult a qualified lawyer for advice on their specific circumstances.