Deployable Cloudflare Worker for the BYO Cloudflare integration tier. Customers deploy this to their own Cloudflare account, paste their Ooky API key, and traffic for their domain is intercepted at the edge - no DNS change to a vendor zone.
This is a template repo (this directory pushed to https://github.com/cloudweld/worker-template).
Most customers never need this. The Ooky dashboard deploys this Worker into your Cloudflare account for you: you paste one pre-scoped API token and Ooky uploads the script, sets the
OOKY_API_KEYsecret, and binds your route. Use the manual steps below only if you want to self-manage the deploy, or your Cloudflare account won't let you mint an API token.The dashboard uploads a bundled build of
src/, produced bynpm run bundleand committed atbackend/src/assets/worker-bundle/. Change anything insrc/and you must re-run that command and commit the result, or__tests__/bundleParity.test.mjsfails.
A Worker only intercepts your site if it's bound to your domain's routes. A
plain wrangler deploy (or the one-click button) with the routes block still
commented out deploys the Worker to a *.workers.dev URL bound to zero of
your routes - it never sees real traffic. The deploy "succeeds" and the Ooky
dashboard may even flip to "Connected", but every AI manifest endpoint and all
bot analytics are silently dead.
You must edit wrangler.toml first:
- Uncomment the
routesblock and set it to your domain:routes = [ { pattern = "your-domain.com/*", zone_name = "your-domain.com" } ]
- Set
OOKY_DOMAINin[vars]to your registered Ooky domain (replace theYOUR_DOMAINplaceholder - the Worker treats the literal placeholder as unconfigured and returns a loud error instead of silently failing). - Set the top-level Worker
nameto a unique value for this hostname, with a short random or hash suffix, for exampleooky-example-com-a13f09c2. Never reuse the old account-globalooky-workername across domains: a later deploy would replace the code and secrets behind every route that points to it. The runtime also verifies the request hostname and passes a mismatched legacy route straight through to its origin.
The one-click "Deploy to Cloudflare" button is NOT sufficient on its own. It scaffolds the Worker but cannot wire your routes for you. After clicking it you still have to do STEP 1 above, or the integration is a no-op.
After deploying, run the self-diagnostic to confirm everything is wired:
curl -s https://your-domain.com/__ooky/health | jqIt reports whether the Worker is bound to your domain, whether OOKY_DOMAIN and
OOKY_API_KEY are set, and exactly what to fix if not. If you hit it on the
*.workers.dev URL, it will tell you the routes aren't wired.
git clone https://github.com/cloudweld/worker-template.git
cd worker-template
npm install
# STEP 1 (REQUIRED): set OOKY_DOMAIN, choose a unique per-host `name`, and
# uncomment the `routes` block.
$EDITOR wrangler.toml
# Set the Bearer token (from your Ooky dashboard → Integrations → Worker)
npx wrangler secret put OOKY_API_KEY
# (Optional) Create a KV namespace for cross-request bot-registry caching
npx wrangler kv namespace create OOKY_BOT_CACHE
# Paste the printed `id` into wrangler.toml under [[kv_namespaces]]
npx wrangler deploy --config wrangler.tomlThe button scaffolds the Worker into your account but does not wire your
routes - you must still complete STEP 1 (uncomment routes, set
OOKY_DOMAIN) or the Worker intercepts nothing.
For each request that reaches the bound route, the template runs this decision flow:
- Loads the bot-UA registry from
/api/public/bots. By default this is cached in memory per isolate (each new isolate refetches on its first request). If you bind the optionalOOKY_BOT_CACHEKV namespace, it's also cached in KV for an hour so isolates share it. - Checks the
User-Agentagainst the registry. If it's a known AI bot, attempts a non-blocking bot event to Ooky's ingest endpoint with your per-domain Bearer token (and the request'scf.countryfor geo). This delivery is best-effort, so the resulting event feed is not a complete request log. - For non-bot traffic, detects humans arriving from an AI platform
(ChatGPT/Perplexity/Claude/…) via the
Refererheader or autm_sourceparam, and attempts a non-blockingai_referralevent so the dashboard's attribution lands. - If the path matches one of the well-known AI URLs, serves the manifest from
Ooky's public CDN:
/llms.txt/llms-full.txt/agents.md/.well-known/ai-manifest.json(and/ai-manifest.json)/.well-known/mcpand/mcp(full MCP JSON-RPC, see below)
- If the request is a bot on a content page (a
GETthat wants HTML, not an asset), the Worker fetches the latest published, parity-gated distilled HTML for that path from Ooky's bearer-authed per-page API and serves it in place of your origin markup. When nothing is published the API returns204and the request falls through to your origin. Humans always get your real page. - Otherwise, the request passes through to your origin unchanged.
/mcp and /.well-known/mcp speak the MCP JSON-RPC 2.0 protocol that real
clients (Claude, the MCP Inspector, ChatGPT connectors) use:
GETreturns the static descriptor from the public CDN.POSThandlesinitialize,tools/list, andtools/callfor theget_brand_infotool, plus the legacy{ tool, arguments }shape.OPTIONSreturns CORS preflight headers. This mirrors@ooky/sdk's MCP behaviour; the server identifies itself asooky-<your-domain>.
This tier exposes only get_brand_info (product/feed tools require feed data
this tier doesn't have).
The BYO-Worker tier intercepts bots, fires analytics, and serves the well-known AI artifacts. It is intentionally simpler than the Full-DNS tier (where you point your domain's DNS at Ooky):
| Capability | BYO Worker (this) | Full-DNS |
|---|---|---|
| Bot detection + AI-Sessions analytics | ✅ | ✅ |
| AI-referral attribution (human from ChatGPT/…) | ✅ | ✅ |
Serve /llms.txt, /llms-full.txt, /agents.md, AI manifest |
✅ | ✅ |
MCP JSON-RPC endpoint (get_brand_info) |
✅ | ✅ (+ product tools) |
| Distilled / cleaned-HTML served to bots on normal pages | ✅ (when published) | ✅ |
| JSON-LD injection into your human HTML | ❌ | ✅ |
| Content negotiation rewrite of your human HTML | ❌ | ✅ |
| Reverse-DNS / IP-CIDR bot verification | ❌ (UA-only) | ✅ |
Important: cleaned-HTML serving on this tier starts once the integration is installed and an eligible page artifact is published. It is fetched from Ooky's per-page API (a customer-deployed Worker has no R2 binding, so it reads the artifact over HTTP rather than from the edge store the managed Worker uses). When a page has nothing published, a bot hitting a normal page gets your origin's HTML unchanged. JSON-LD injection into human pages and content-negotiation rewrites remain Full-DNS differentiators; they require Ooky inline in front of every request.
- Timeouts: every upstream fetch (manifest serve, event ingest, bot-registry
refresh) carries an
AbortSignaldeadline so a hung Ooky API never stalls your site. - Ownership-safe revalidation: manifest and per-page artifact fetches bypass the Workers Cache API on every request. A hostname can move between Ooky workspaces, so the former owner's body is never a stale availability fallback.
- No artifact caching: success and error responses are private and
no-store; a pre-publish 404 or transient 5xx cannot stick after recovery. - Ownership proof: every successful manifest or page artifact must include a valid hostname claim ID, generation, exact edge namespace, and the fresh request nonce. Fetches carry the domain-scoped Bearer key; revoked or former- owner installs and replayed intermediary 200s fail closed.
| Variable | Where set | Required | Description |
|---|---|---|---|
routes |
wrangler.toml |
Yes | The domain/route the Worker binds to. Without it the Worker intercepts nothing (see STEP 1). |
OOKY_DOMAIN |
wrangler.toml [vars] |
Yes | The domain you registered in the Ooky dashboard. Must match the verified domain. The literal YOUR_DOMAIN placeholder is treated as unconfigured. |
OOKY_API_KEY |
wrangler secret put |
Yes | Per-domain Bearer token (ooky_sk_*) from the Ooky dashboard. |
OOKY_API_BASE |
wrangler.toml [vars] |
No | Defaults to https://api.ooky.ai/api. Override only if you self-host Ooky. |
OOKY_BOT_CACHE |
KV binding | No | Optional. Caches the bot registry in KV across requests/isolates. Without it, each new isolate refetches on its first request (in-memory only). |
ORIGIN_SERVICE |
Service binding | No | Required when replacing an existing site Worker's route. A site Worker on a Custom Domain can use native passthrough. See below. |
Cloudflare distinguishes a Worker on a Custom Domain from a Worker on a
route. Native passthrough (fetch(request)) reaches a normal server or a
site Worker on a Custom Domain. It cannot invoke another same-zone route Worker.
A route pattern maps to exactly one script. Replacing an existing site's route requires binding that original script so it continues to serve the site. Do not overwrite overlapping wildcard or path routes without reviewing their behavior; the Ooky guided setup blocks these ambiguous configurations.
Bind your site's Worker instead:
# wrangler.toml
[[services]]
binding = "ORIGIN_SERVICE"
service = "your-site-worker-name"Passthrough now invokes the bound Worker. Verify with
/__ooky/health?check_origin=1: origin.reachable must be true, and origin.mode
is service for a binding or fetch for native passthrough. The probe performs a
sanitized homepage request, cancels its body, and times out after eight seconds.
The regular health endpoint only checks configuration. A failing service returns
502 to visitors without replaying their request into a different origin.
Cloudflare documents these distinct paths in Routes and Custom Domains.
# Self-diagnostic - checks routes/domain/key wiring and tells you what's wrong:
curl -s 'https://your-domain.com/__ooky/health?check_origin=1' | jq
# Bot path + a manifest path:
curl -s https://your-domain.com/llms.txt | head
curl -I -H "User-Agent: GPTBot/1.0" https://your-domain.com/Within ~30 seconds the integration in your Ooky dashboard should flip to "Connected" and the AI Sessions tab should show the event.
| Symptom | Likely cause |
|---|---|
| Whole site returns HTTP 522 right after deploying this Worker | An existing site Worker route may have been replaced without a service binding, or the server is unreachable. Check origin in the health probe; bind the original route Worker when required. Custom Domain Workers can use native passthrough. |
/llms.txt returns origin's response |
Worker route not bound to your domain. Complete STEP 1 (uncomment routes). Run /__ooky/health to confirm. |
/__ooky/health reports served_on_workers_dev: true |
You're hitting the *.workers.dev URL - the routes block isn't wired. |
Manifest endpoint returns a loud 500 about YOUR_DOMAIN |
OOKY_DOMAIN is still the placeholder. Set it in wrangler.toml and redeploy. |
| Manifest endpoint returns 404 | No published manifest yet. Publish from the Ooky dashboard's Builder. |
| Manifest endpoint returns 401 | OOKY_API_KEY is missing, revoked, or belongs to a different/currently transferred hostname. Install the current domain key. |
[ooky] ingest responded 401 in wrangler tail |
OOKY_API_KEY secret missing or wrong. Re-run wrangler secret put OOKY_API_KEY. |
| Bot events not appearing | Check wrangler tail to confirm the Worker is being invoked and watch for [ooky] ingest warnings. |
npm install
npm test # vitest unit tests
npx wrangler deploy --config wrangler.toml --dry-run # validate without deployingAdds an explicit origin readiness probe at /__ooky/health?check_origin=1.
Guided setup can distinguish working routes from a configured Worker whose
origin fails. Failed origin services return a controlled 502 without replaying
streamed mutations. Setup guidance now distinguishes Custom Domains from routes.
Adds the optional ORIGIN_SERVICE service binding for sites that have no origin
server because the site is itself a Worker (Workers Static Assets, Pages). All
three origin-passthrough paths now go Worker-to-Worker when it is bound, instead
of dialing an origin that does not exist and returning 522 on every request.
/__ooky/health reports origin_service_bound. Unbound, behavior is unchanged.
TEMPLATE_VERSION = "0.2.0".
Security release: ownership-sensitive manifest and page artifacts now bypass
the Workers Cache API, are never stale-served from isolate memory, and return
private no-store responses. TEMPLATE_VERSION = "0.1.1".
Initial release of the BYO-Worker template (TEMPLATE_VERSION = "0.1.0").
- Bot detection against the Ooky UA registry (
/api/public/bots), cached in-memory per isolate and optionally in KV (OOKY_BOT_CACHE). - Manifest serving of the well-known AI URLs (
/llms.txt,/llms-full.txt,/agents.md,/.well-known/ai-manifest.json,/ai-manifest.json) from Ooky's public CDN. - Cleaned-HTML serving to detected bots on content pages when an artifact is published, fetched from Ooky's bearer-authed per-page API.
- Event logging: non-blocking bot events and
ai_referralevents fired to Ooky's ingest endpoint with the per-domain Bearer token. - MCP endpoint (
/mcp,/.well-known/mcp): JSON-RPC 2.0 (initialize,tools/list,tools/callforget_brand_info) plus the legacy Ooky shape. - Health endpoint (
/__ooky/health): self-diagnostic that reports route, domain, and key wiring and flags the*.workers.devno-op trap. - Stale-serve resilience: timeouts on every upstream fetch, last-good manifest served through a transient 5xx/timeout, and no caching of error responses.
The compatibility_date in wrangler.toml is pinned to 2026-04-01 so the
Workers runtime behaviour stays fixed for this release; bump it deliberately when
adopting newer runtime semantics.
MIT.