Cloudflare integration
Cloudflare Pages and Workers monitoring
BugOtter imports your Cloudflare Pages projects and Workers on custom domains with a read-only token it uses once. Uptime checks start on each domain from three regions. A Worker route or Pages Function serves analytics from your own domain, and @sentry/cloudflare sends Worker errors to BugOtter.
- Used onceimport token, never stored
- 2read permissions, nothing else
- 3 regionscheck each domain

Two read permissions, used once
Pages Read and Workers Scripts Read. The token lists your projects while you pick and isn't stored.A few lines past ad blockers
A Worker route or a Pages Function serves the script from your own domain.Worker errors, Sentry's SDK
@sentry/cloudflarewith your BugOtter DSN. No Sentry account needed.
Import Pages projects and Workers
Create a custom API token
Open dash.cloudflare.com/profile/api-tokens → Create token → Custom token. Add Account · Cloudflare Pages · Read and Account · Workers Scripts · Read. Pick the accounts it may see.Paste it in BugOtter
Click Import from Cloudflare. You get every Pages project, with its custom domain when it has one (otherwise itspages.devaddress), and every Worker on a Custom Domain.Pick what to watch
Checks start right away from US East, Europe and US West, with an outage only when two regions agree. SSL and domain expiry are watched too. The token isn't stored.

- 30 days at a glance. Amber marks a day with some downtime.
- Response time, median and p95, with the slowest region named.
- Three regions. An outage only counts when two agree.
Analytics past ad blockers, the Cloudflare way
Ad blockers drop 20–40% of visitors for most analytics. On Cloudflare, a few lines of Worker code serve BugOtter from your own domain. Pages' _redirects can't proxy to another domain, so it's a Function there too.
One small helper does the forwarding for both cases. Put it in src/ for a Worker, or at the project root next to functions/ for Pages:
// bo-proxy.ts: forwards three paths to BugOtter, nothing else
const BO = "https://bugotter.com";
export async function forward(request: Request, path: string, key: string) {
const target: Record<string, string> = {
"bo.js": `${BO}/bo.js`,
"api/collect": `${BO}/api/collect?via=${key}`,
"api/errors": `${BO}/api/errors?via=${key}`,
};
const url = target[path];
if (!url) return new Response("Not found", { status: 404 });
// Only what BugOtter checks. Your site's cookies stay on your site.
const headers = new Headers();
for (const h of ["content-type", "user-agent", "origin", "referer"]) {
const v = request.headers.get(h);
if (v) headers.set(h, v);
}
return fetch(url, {
method: request.method,
headers,
body: request.method === "POST" ? await request.text() : undefined,
});
}Workers, or any site behind Cloudflare
Add a Worker on the route example.com/_bo/*. Routes need the hostname proxied by Cloudflare (the orange cloud), and the site behind it can be anything: a Worker, a server, or another host.
If your site already is a Worker, call forward() from its own fetch for paths under /_bo/ instead.
// src/index.ts: a small Worker on the route example.com/_bo/*
import { forward } from "./bo-proxy";
export default {
async fetch(request, env) {
const path = new URL(request.url).pathname.replace(/^\/_bo\//, "");
return forward(request, path, env.BUGOTTER_PROXY_KEY);
},
} satisfies ExportedHandler<{ BUGOTTER_PROXY_KEY: string }>;// wrangler.jsonc
{
"name": "bo-proxy",
"main": "src/index.ts",
"compatibility_date": "2026-11-04",
"routes": [{ "pattern": "example.com/_bo/*", "zone_name": "example.com" }]
}
// then: npx wrangler secret put BUGOTTER_PROXY_KEYCloudflare Pages
Add a Pages Function. A [[path]] file name matches everything under /_bo/. Set BUGOTTER_PROXY_KEY in the project's variables and secrets.
// functions/_bo/[[path]].ts: a Pages Function for /_bo/*
import { forward } from "../../bo-proxy";
export const onRequest: PagesFunction<{ BUGOTTER_PROXY_KEY: string }> = ({ request, params, env }) =>
forward(request, (params.path as string[]).join("/"), env.BUGOTTER_PROXY_KEY);Then change the script tag to src="/_bo/bo.js".
Check it once: curl -sI https://yourapp.com/_bo/bo.js should answer 200. Your proxy key is on the app's Traffic tab in BugOtter. Keep the ?via= part: it proves visits came through your proxy, and it only lives in server config, never in the page.

- Visitors, against the period before (the dashed line).
- Markers for big payments, error spikes and deploys.
- Bots kept out of the count.
Errors from Workers and Pages Functions
Browser errors come from the script. For Worker code, use Sentry's Cloudflare SDK with your BugOtter DSN. You don't need a Sentry account.
Store the DSN with npx wrangler secret put BUGOTTER_DSN or as a variable.
// src/index.ts
import * as Sentry from "@sentry/cloudflare";
export default Sentry.withSentry(
(env: Env) => ({
dsn: env.BUGOTTER_DSN,
dataCollection: { userInfo: false, cookies: false, httpBodies: [], databaseQueryData: false },
}),
{
async fetch(request, env, ctx) {
return handle(request, env, ctx); // your Worker, unchanged
},
} satisfies ExportedHandler<Env>,
);
// wrangler.jsonc needs: "compatibility_flags": ["nodejs_compat"]
// and a compatibility_date of 2024-09-23 or later// functions/_middleware.ts
import * as Sentry from "@sentry/cloudflare";
export const onRequest = [
// Sentry first, then any middleware of your own
Sentry.sentryPagesPlugin((context) => ({ dsn: context.env.BUGOTTER_DSN })),
];The dataCollection line is for SDK v11. Leave out tracesSampleRate: BugOtter keeps errors, not traces, so spans are accepted and dropped.
Running SvelteKit, Astro or Nuxt on Cloudflare? Their Sentry SDKs need this Cloudflare SDK underneath. See each framework page.
Source maps for browser bundles: add the upload to the build command, like npm run build && npx bugotter sourcemaps dist --delete. On Pages, the CLI tags them with CF_PAGES_COMMIT_SHA by itself. With Workers Builds, pass --release $WORKERS_CI_COMMIT_SHA. More in the source maps guide.
Mark deploys from your build
BugOtter doesn't read deploys from Cloudflare by itself yet
npx bugotter deploy. The CLI needs BUGOTTER_PROJECT and BUGOTTER_KEY (the upload key: keep it a secret, not a plain variable).- Pages: end the build command with
&& npx bugotter deploy. It marks the deploy when the build finishes, a minute or so before it's live. - Workers Builds: make the deploy command
npx wrangler deploy && npx bugotter deploy --version $WORKERS_CI_COMMIT_SHA. - GitHub Actions: run
npx bugotter deployafter the deploy step, or point a GitHub Deployment statuses webhook at your app's deploy URL.
Issues then say “started 4 min after deploy c0ffee1”, and release health compares each deploy with the one before.

- Deploy check. After each Cloudflare deploy: new errors, error rate, speed and sales against the day before.
- New errors name their release, so you know which change to look at.
- Who it hit: events and people, per issue.
A status page for your Cloudflare app
Cloudflare's status page covers Cloudflare. Yours should cover your app: the home page, an API path your app can't work without, and sign-in.
Add each as a check with an expected status, word or JSON value, so an error page that answers 200 still fails. Then:
- Turn on the status page at
bugotter.com/status/your-app: uptime, incidents and your updates, never errors or revenue. - Pro can serve it from your own domain, like
status.yourapp.com. Add the records it shows in your Cloudflare DNS. - People can subscribe to updates, and a badge shows your uptime in the README.
- Cron Triggers can call a heartbeat URL when they finish, so a run that's late or fails alerts you.

- One line for your users: all good, or what isn't.
- Uptime per check, day by day.
- Incidents and your updates. Never errors, logs or revenue.
Or ask your coding agent
Connect BugOtter to Claude Code, Cursor or Codex once over MCP. It signs in through your browser, read-only unless you allow changes. Then paste one line.
claude mcp add --transport http --scope user bugotter https://bugotter.com/api/mcpThen ask, in plain words:
Add the BugOtter ad-blocker proxy to this Cloudflare project: a Pages Function at functions/_bo/[[path]].ts, or a route in our Worker, then switch the script to /_bo/bo.js.
Wrap this Worker with @sentry/cloudflare using my BugOtter DSN, server errors only.
Using BugOtter, list this app's errors since the last deploy and fix the newest one.
Cursor, VS Code, Codex and the rest have their own one-step setup at Docs: your agent (MCP). Every setup screen in BugOtter also has a Copy prompt for your agent button with your keys filled in.
Questions
Does BugOtter keep my Cloudflare token?
No. It's used once, to list your Pages projects and Workers while you pick, and never stored. It only needs two read permissions, and you can delete it in Cloudflare right after the import.
Why isn't my Worker in the import list?
The import lists Workers on Custom Domains. Workers that answer on a route of a zone, or only on workers.dev, aren't in that list: add their URLs by hand. Checks work the same.
Can I proxy with Cloudflare Pages _redirects?
No. Cloudflare's _redirects can rewrite within your own site but can't proxy to another domain. A Pages Function at functions/_bo/[[path]].ts does the same job in a few lines.
Do Cloudflare deploys show up by themselves?
Not yet. BugOtter reads deploys from Vercel automatically, but not from Cloudflare. Add npx bugotter deploy to the build or deploy command, or send a GitHub deployment webhook if you deploy from GitHub Actions.
My uptime checks get a Cloudflare challenge. What now?
Bot Fight Mode or a WAF rule can challenge outside checkers, which then look like outages. BugOtter's checks always send the user agent BugOtter/1.0 (+https://bugotter.com/bot). Add a WAF skip rule for it, or send a header the rule lets through: each check can carry its own headers, such as a Cloudflare Access service token.
Are Worker stack traces source-mapped?
Browser stacks are, from the maps you upload. Worker stacks are shown as the SDK sends them. Wrangler's upload_source_maps setting is for Cloudflare's own dashboard, not BugOtter.
Sources
Checked Nov 4, 2026 against Cloudflare's docs on API token permissions, Workers routes, Pages redirects, Pages Functions routing and Workers Builds, and Sentry's Cloudflare guide. BugOtter isn't affiliated with Cloudflare or Sentry.
Watch every app you ship, from one calm list.
14 days of everything, no card needed. Plans from $10 a month, billed yearly.