Cloudflare Workers · Supabase · pgvector

Drop-in AI chat
for any website.

Answers from your own docs. Captures leads while it talks. One script tag, pasted once — no build step on the client's side.

Paste before </body>
<script
  src="https://conversekit-widget.pages.dev/widget.js"
  data-bot-id="YOUR_BOT_ID"
  defer></script>
Open the dashboard

The chat bubble in the corner is the real widget, running on this page.

01

How it works

Three steps, and the third one never ends

Onboarding a client is a row in a table and a script tag. There is no per-customer deploy, no rebuild, and nothing to install on their side.

STEP 01

Give it something to say

Paste a business description, services, hours and an FAQ — or point it at a URL and let it read. Longer material becomes a knowledge source: chunked, embedded and searched at question time.

STEP 02

Paste one tag

The snippet goes anywhere before the closing body tag. The widget styles itself from the bot's own brand colour and only answers on the origins you allow.

STEP 03

It answers, and it listens

Replies stream token by token. When a visitor shows intent, the model collects a name, email or phone number mid-conversation and files it as a lead you can export.

02

AI providers

Eleven vendors, one interface

Most vendors speak the OpenAI chat-completions shape, so they are configuration rather than code — one adapter, many entries. Only Anthropic, Google and Workers AI need their own translation layer. Switching vendor is a dropdown, per bot.

OpenAI Paid
Anthropic Claude Paid
Google Gemini Free tier
Groq Free tier
OpenRouter Free tier
Mistral Free tier
Workers AI Free tier
DeepSeek Paid
Together AI Paid
Ollama Local
LM Studio Local
Any OpenAI-compatible Custom

It runs on nothing

Groq for chat and Cloudflare Workers AI for embeddings run the entire loop — ingest, retrieve, answer — at no cost. That is the platform default, and it is verified rather than theoretical.

Bring your own key

Each bot can carry its own vendor credentials, or fall back to the platform's. Keys are write-only through the API: once stored, they are redacted from every response and the UI shows the last four characters.

Streaming, with a net

Replies arrive over SSE. If the stream fails for any reason — a proxy, an extension, a vendor hiccup — the widget silently retries against the buffered endpoint, and the visitor sees an answer either way.

03

Knowledge

Answers from your documents, not from the internet

Text, markdown and URLs become a searchable corpus. At question time the query is embedded, matched against that bot's chunks by cosine similarity, and the best passages are assembled into the prompt with their sources.

Tuned per bot

The number of passages retrieved, a similarity floor and chunk size are per-bot settings, not global constants. A dense product manual and a short FAQ do not want the same retrieval.

Retrieval never fails the visitor

A bot with no corpus, or an embedding vendor having a bad minute, falls back to the plain knowledge-base prompt instead of failing the turn. A degraded answer beats an error message.

Inspect what it found

The dashboard shows the chunks a document produced and lets you reindex a source after editing it, so "why did it say that?" is a question you can actually answer.

768Embedding dimensions, fixed platform-wide so every vendor can serve it
pgvectorVectors live in Postgres beside the tenant data, not in a separate store
HNSWApproximate nearest-neighbour index over every bot's chunks
SSEToken-by-token streaming with a buffered fallback
04

Multi-tenant

Built for someone running this for other people

One Worker and one Pages site serve an unlimited number of client bots. Isolation is enforced in the database, not in application code that a future refactor can quietly drop.

Row-level security

Every tenant-scoped table carries an RLS policy keyed off the signed-in user's memberships. Two organizations cannot see each other's bots, leads or conversations — proven by a test that authenticates as one org and asks for the other's ids directly.

Origin lock

Each bot carries a list of allowed origins, normalised and matched exactly — scheme and port included. A request from anywhere else is refused with a 403 before the model is ever called.

Signed sessions

Conversation ids are minted and signed by the server. The widget never invents one, because a guessable id would let anyone replay it and read another visitor's transcript.

05

Install

One tag. Any site.

Create a bot in the dashboard, fill in what it should know, then paste this with your own bot id.

Paste before </body>
<script
  src="https://conversekit-widget.pages.dev/widget.js"
  data-bot-id="YOUR_BOT_ID"
  defer></script>