The pieces
All of these are created by the Deploy button or by
wrangler deploy. See Deploy to Cloudflare.
From a visitor’s message to an AI reply
1
The loader starts on your page
widget.js loads from your desk with data-key. It starts capturing debug context in memory, opens a small live connection so you see the visitor on the Visitors page, and adds the chat frame (/widget?key=…). The Worker serves that frame with a frame-ancestors policy built from your Allowed websites, so other sites can’t embed your chat.2
The visitor gets a token
The frame asks the Worker for a visitor token. It identifies this browser’s anonymous contact. If your page passes a signed identity token, the contact becomes a verified customer instead. See Identify users.
3
The first message creates the conversation
The first message goes over HTTP, which creates the conversation in D1 and hands the message to its
Conversation Durable Object. The frame then opens a WebSocket to that object. Messages typed before the conversation exists are held and sent into it once its socket opens.4
The Conversation object records and broadcasts
The object gives the message the next sequence number, writes it to D1 and sends it to every socket on the conversation: the visitor’s and any teammate who has it open. It also tells the
WorkspaceHub, which updates every teammate’s inbox. Messages are idempotent per client message id, so a retry never duplicates one.5
An AI turn runs from an alarm
If the conversation is handled by the AI, the object sets an alarm for now. The alarm runs one AI turn. It first checks whether the AI should answer at all:
- the AI is turned on,
- the visitor didn’t ask for a person,
- the AI hasn’t reached
maxRepliesin this conversation (8 by default, set ininstructions.md), - the workspace hasn’t reached its monthly reply cap (2,000 by default, in Settings → AI).
6
Search, then answer
The turn searches your knowledge with hybrid search: vectors in the
KnowledgeIndex object and keywords in D1’s full-text index, merged and reranked. It then runs the model with your instructions.md, tasks, actions, the masked debug context, the verified customer (if any) and the page’s actions. The model may call up to 5 tools in a turn.The reply streams to the visitor word by word, with citations already resolved to source chips. The finished reply is saved with the id ai:<seq>, so a retried alarm can never answer the same message twice.7
Follow-ups and labels come later
A separate fast job adds suggested follow-up questions under answers that came from your knowledge. Once a chat goes quiet, the 15-minute cron gives it a topic label for the Dashboard.
Handoff to a person
The AI only answers while a conversation’s handling isai. These switch it to human:
- a teammate replies (an internal note doesn’t count),
- the visitor presses “Talk to a person” or asks for one,
- the model calls its
handofftool, for example when the customer needs something only staff can do, or a topic inhandoffTopicscomes up, - the reply limit or the monthly cap is reached,
- the AI is off or its provider fails.
Realtime
- Teammates, visitors and the loader talk to Durable Objects over WebSockets. The Worker authenticates every upgrade first: a teammate by their session cookie, a visitor by their token sent as the WebSocket’s second subprotocol. It then forwards the socket to the object.
- Clients ping every 30 seconds. Durable Objects answer pings automatically, even while hibernated, so idle chats cost almost nothing.
- A socket with no ping for 75 seconds counts as gone. It disappears from the visitor list, presence and auto-assignment, and a sweep closes it. Tabs closed without a goodbye and connections cut by a deploy don’t linger.
- Internal notes, tags and topics only go to sockets tagged as teammates. They never reach a visitor or the AI.
What’s stored where
Tokens and secrets the desk issues itself (sessions, invites, API tokens) are stored only as SHA-256 hashes.
No external services
A working desk needs nothing outside Cloudflare:- Sign-in uses passkeys, so there’s no email service or OAuth provider. The owner is created with
SETUP_TOKEN; teammates join through invite links. - The AI runs on Workers AI by default, so there’s no API key to get.
- Search runs on D1 and a Durable Object, so it works in local development and with one-click deploy.
- Notifications use standard Web Push with a key the desk creates on first use.