Quick Install
Embed Jeremy with a single line of code. The widget injects itself, loads all styles and assets, and connects to your API endpoint.
HTML
Add this to your page where you want the chat widget to appear (usually before </body>):
<script src="https://jeremy-chat-bot.pages.dev/jeremy.js" data-api="/api/chat" data-orchid-path="orchid/"></script>
Script Attributes
| Attribute | Required | Default | Description |
|---|---|---|---|
data-api |
No | /api/chat |
API endpoint path for chat requests. Must return {"reply": "..."} |
data-orchid-path |
No | ./orchid/ |
Base path to orchid video directory. Videos: orchid-greeting.webm, orchid-idle.webm, orchid-responding.webm, orchid-bow.webm |
Example with Custom Paths
<script
src="https://cdn.example.com/v1/jeremy.js"
data-api="https://api.example.com/v1/chat"
data-orchid-path="https://cdn.example.com/assets/orchid/"
></script>
CSS Customization
Jeremy exposes CSS custom properties so you can easily match your brand. Define these in your page's <style> or external CSS before loading jeremy.js.
Color & Branding
:root {
--jeremy-blue: #0483ca; /* Primary brand color */
--jeremy-blue-dark: #036ba5; /* Hover/active state */
--jeremy-font: 'Lora', Georgia, serif; /* Body text */
--jeremy-heading-font: 'Marcellus SC', serif; /* Headers */
}
Layout & Dimensions
:root {
--jeremy-panel-width: 380px; /* Chat panel width */
--jeremy-panel-height: 580px; /* Chat panel height */
--jeremy-orchid-height: 220px; /* Orchid video area height */
--jeremy-toggle-size: 60px; /* Chat toggle button size */
--jeremy-border-radius: 12px; /* Border radius */
}
Example: Custom Brand Colors
:root {
--jeremy-blue: #ff6b35; /* Your brand orange */
--jeremy-blue-dark: #e05a2d; /* Darker shade */
--jeremy-font: 'Inter', sans-serif; /* Your font */
}
All CSS is scoped with #jeremy- ID and class prefixes to prevent conflicts with your page's styles.
Jeremy & the Orchid
The orchid is Jeremy's animated mascot character. It appears at the top of the chat panel and responds with different animations as you chat.
Orchid States
- Greeting — plays when the chat first opens
- Idle — loops continuously when waiting for input
- Responding — plays while Jeremy is thinking of a response
- Bow — graceful bow animation before revealing the response
Customizing the Orchid Area
You can control the orchid display size and background with CSS:
:root {
--jeremy-orchid-height: 180px; /* Smaller on mobile */
}
The orchid video files must be WebM format. Place them in your orchid/ directory:
orchid/orchid-greeting.webm— plays on chat openorchid/orchid-idle.webm— loops continuouslyorchid/orchid-responding.webm— loops while processingorchid/orchid-bow.webm— plays before response reveal
Chat Window
The chat panel is fully customizable. Control colors, fonts, sizing, and more with CSS custom properties.
Message Bubbles
| Element | CSS Class | Description |
|---|---|---|
| User message | .jeremy-msg-user |
Right-aligned, primary blue background |
| Assistant message | .jeremy-msg-assistant |
Left-aligned, light gray background |
| Typing indicator | .jeremy-typing |
Animated three-dot animation |
Session Persistence
Chat history is automatically saved to sessionStorage. When a user refreshes the page, their conversation is preserved. Each browser session gets a unique session_id sent to your API for tracking and logging.
CTA Tracking
When a user clicks a link (Calendly booking, phone number, etc.) within a chat message, the widget automatically marks it as cta_clicked: true and sends this flag to your API.
API Configuration
Jeremy communicates with your backend API endpoint. By default, it uses /api/chat, but you can customize this with the data-api attribute.
Hosted Endpoints
Jeremy's API is hosted at:
| Endpoint | Method | Description |
|---|---|---|
https://jeremy-chat-bot.pages.dev/api/chat |
POST |
Main chat endpoint — send messages, receive AI replies |
https://jeremy-chat-bot.pages.dev/demo |
GET |
Live interactive demo |
https://jeremy-chat-bot.pages.dev/jeremy.js |
GET |
Embeddable widget script |
API Request Format
POST https://jeremy-chat-bot.pages.dev/api/chat
{
"messages": [
{ "role": "user", "content": "Hello!" },
{ "role": "assistant", "content": "Hi there!" }
],
"session_id": "uuid-here",
"cta_clicked": false
}
API Response Format
{
"reply": "Your response text here. Can include HTML <a> tags.",
"session_id": "uuid-here"
}
Response Notes
- The
replyfield is required. It's displayed as the assistant's message. - You can include HTML links:
<a href="..." target="_blank">text</a> - The widget will sanitize HTML to prevent XSS — only
<a>and<br>tags are allowed. - The
session_idin the response is optional and mirrors the request.
Error Handling
If your API returns an error or the request fails, Jeremy displays a fallback message. Make sure your API is accessible from the client's browser (handle CORS appropriately).
Environment Variables
Jeremy's backend requires several environment variables. These are configured in Cloudflare Pages (for the API functions) and in wrangler.toml (for D1 and KV bindings).
Required Secrets (Cloudflare Pages Dashboard)
Set these as environment secrets in your Cloudflare Pages project settings under Settings → Environment → Production/Preview:
OPENAI_API_KEY
Your OpenAI API key for language detection and translation.
sk-proj-xxxxxxxxxxxxx
ANTHROPIC_API_KEY
Your Anthropic API key for Claude AI chat responses.
sk-ant-xxxxxxxxxxxxx
CALENDLY_TOKEN
Your Calendly API token for scheduling appointments (optional but recommended).
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
ALLOWED_ORIGIN
CORS allowed origin (e.g., your website domain). Defaults to * if not set.
https://yourdomain.com
D1 & KV Bindings (wrangler.toml)
Configure these bindings in your wrangler.toml file. The API code references these as env.DB and env.RATE_LIMIT:
# D1 Database binding
[[d1_databases]]
binding = "DB"
database_name = "jeremy-chat"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# KV namespace binding for rate limiting
[[kv_namespaces]]
binding = "RATE_LIMIT"
id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
preview_id = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
.env.example Template
Reference file for developers:
# OpenAI API (language detection & translation)
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxx
# Anthropic API (Claude AI responses)
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxx
# Calendly API (appointment scheduling, optional)
CALENDLY_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# CORS allowed origin (defaults to * if not set)
ALLOWED_ORIGIN=https://yourdomain.com
# D1 & KV bindings are configured in wrangler.toml, not here
# D1 binding: env.DB
# KV binding: env.RATE_LIMIT
Setup Instructions
- Get API keys: Sign up for OpenAI and Anthropic, create API keys.
- Cloudflare Pages: In your project settings, add the secrets as environment variables.
- D1 Database: Create a D1 database in Cloudflare, update
wrangler.tomlwith the ID. - KV Namespace: Create a KV namespace, update
wrangler.toml. - Deploy: Push your code and Cloudflare will automatically load the secrets and bindings.