Deterministic, public-safe HTTP diagnostics and browser fixtures on Cloudflare Workers.
Quick start · Try it · Fixture catalog · Architecture · Documentation · Validation · Security
BTLR HTTP gives HTTP clients, crawlers, browser automation, and rendering pipelines a controlled target for testing request inspection, response semantics, browser capabilities, and synthetic access challenges. Fixtures are deterministic by default, strictly bounded, inspectable, and designed to behave honestly on the Workers runtime.
- HTTP requests — methods, repeated query values, headers, cookies, JSON, forms, text, binary bodies, authentication, and redaction.
- HTTP responses — status codes, safe response headers, redirects, body formats, compression, caching, validators, negotiation, ranges, delays, and streams.
- Browser behavior — hydration, rendering, JavaScript, Web Workers, WebAssembly, browser storage, interaction, navigation, lifecycle, iframe, and Shadow DOM flows.
- Controlled challenges — synthetic header policies, signed JavaScript tokens, cookies, ordered sessions, interaction checks, mock CAPTCHAs, and block pages.
Every browser fixture exposes stable selectors and a machine-readable completion state. Every resource-intensive fixture has explicit size, time, or state limits.
| Tool | Version | Used for |
|---|---|---|
| Node.js | 22 or newer | Worker, local runtime, and test tooling |
| pnpm | 11.13 | Dependency and script execution |
| Python | 3.12 recommended | Requests and HTTPX contract tests |
| curl | Current stable | Command-line client contract tests |
pnpm is provisioned through Corepack. No global Wrangler installation is required. npm can still invoke package scripts when pnpm is available, but the lockfile, CI, and documented workflow are pnpm-first.
corepack enable
pnpm install --frozen-lockfile
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-contract.txt
cp .dev.vars.example .dev.vars
pnpm run types
pnpm run devWrangler prints the local URL, normally http://localhost:8787.
Open these local entrypoints after startup:
| URL | Purpose |
|---|---|
http://localhost:8787/ |
Searchable fixture directory and examples |
http://localhost:8787/docs |
Comprehensive running-service guide |
http://localhost:8787/openapi.json |
OpenAPI 3.1 document |
http://localhost:8787/browser |
Browser fixture gallery |
http://localhost:8787/challenge |
Controlled challenge gallery |
See the getting-started guide for setup details, local configuration, and common workflows.
Inspect a request and preserve repeated query values:
curl 'http://localhost:8787/get?tag=one&tag=two'Exercise response and navigation behavior:
curl -i http://localhost:8787/status/418
curl -i http://localhost:8787/redirect/2
curl --no-buffer http://localhost:8787/stream/3An inspection response uses a consistent diagnostic envelope:
{
"request": {
"method": "GET",
"query": { "tag": ["one", "two"] }
},
"response": { "status": 200 },
"meta": { "requestId": "…", "timestamp": "…" }
}Direct browser navigation receives readable, indented JSON. Programmatic clients receive the equivalent compact representation unless a fixture is wire-sensitive.
| Category | Representative routes | Guide |
|---|---|---|
| Request inspection | /anything, /get, /post, /headers, /cookies |
Request diagnostics |
| Status, headers, redirects | /status/418, /response-headers, /redirect/2 |
Status and redirects |
| Body formats | /json, /xml, /base64/:value, /bytes/:count |
Body formats |
| Authentication | /basic-auth/:user/:password, /bearer, /proxy-auth |
Authentication |
| Negotiation and methods | /negotiate/accept, /protocol/methods, /protocol/cors |
Protocol negotiation |
| Compression and caching | /gzip, /brotli, /cache/:seconds, /etag/:etag |
Compression and caching |
| Timing, streaming, ranges | /delay/:seconds, /drip, /stream/:count, /range/:bytes |
Timing and streaming |
| Browser fixtures | /browser/* |
Browser fixtures |
| Controlled challenges | /challenge/* |
Challenge fixtures |
| System and schema | /health, /version, /docs, /openapi.json |
System endpoints |
The API reference index maps the full public surface to its detailed contract.
flowchart LR
Client["HTTP client / crawler"] --> Worker
Browser["Browser / automation"] --> Worker
subgraph Worker["BTLR HTTP Cloudflare Worker"]
Middleware["Request context<br/>limits · rate policy · redaction"]
HTTP["HTTP fixtures"]
BrowserRoutes["Browser fixtures"]
Challenges["Controlled challenges"]
Middleware --> HTTP
Middleware --> BrowserRoutes
Middleware --> Challenges
end
BrowserRoutes --> Assets["Workers Static Assets"]
Challenges -->|"ordered sequence only"| DO[("ChallengeSequence<br/>Durable Object")]
HTTP --> Response["Bounded response"]
BrowserRoutes --> Response
Challenges --> Response
Response -.-> Logs["Non-sensitive structured logs"]
One Hono application owns the public surface. The service is stateless except for the narrowly scoped Durable Object that enforces strict order and replay detection in /challenge/sequence; other challenge state is short-lived, signed, and client-carried.
| Path | Responsibility |
|---|---|
src/routes |
HTTP transport and route registration |
src/schemas |
Public input and output schemas |
src/services |
Fixture behavior and reusable policies |
src/middleware |
Request context, limits, rate policy, and presentation |
src/durable-objects |
Strict per-session sequence coordination |
public |
Browser assets served by the Worker |
test |
Unit, integration, contract, wire, and browser evidence |
docs |
Product, API, architecture, security, and operations knowledge |
Read the architecture guide for component boundaries, request flow, state, and platform behavior.
The repository documentation is organized as a GitHub-readable wiki. Start at the documentation home, or jump directly to a guide:
| Guide | Description |
|---|---|
| Getting started | Installation, local configuration, development, and common commands |
| API reference | Public route families and detailed endpoint guides |
| Architecture | Runtime shape, request lifecycle, source boundaries, and state |
| Browser fixtures | Automation contract and browser-required behavior |
| Challenge fixtures | Synthetic challenge behavior and signed state |
| Security | Trust boundaries, abuse controls, limits, secrets, and privacy |
| Testing | Test layers, commands, CI, and evidence rules |
| Operations | Health, logs, monitoring, and incident triage |
| Deployment | Owner-run Cloudflare deployment, rotation, and rollback |
pnpm run validatevalidate is the CI-equivalent gate and runs formatting, documentation links, deployment-configuration contracts, linting, generated binding checks, TypeScript, unit and Worker tests, client contracts, raw-wire tests, Playwright, smoke checks, and a production dry-run build.
| Command | Verifies |
|---|---|
pnpm test |
Unit and Worker integration behavior |
pnpm run test:contract |
Fetch, curl, Python Requests, and HTTPX contracts |
pnpm run test:wire |
Compression, streaming, and transmitted-byte behavior |
pnpm run test:browser |
Rendered DOM, storage, navigation, interaction, and challenges |
pnpm run test:smoke |
Low-load local release checks |
pnpm run build |
Production Worker bundle without publishing |
pnpm run deploy:dry-run |
Owner preflight package and binding validation |
See testing for installation requirements and the complete validation model.
BTLR HTTP is built as an internet-exposed test target:
- Request bodies, generated output, redirects, delays, streams, headers, cookies, and state are hard-bounded.
- Authorization, cookies, API keys, proxy credentials, and similar values are redacted by default.
- Redirects are same-origin and caller-controlled upstream fetching is not implemented.
- Challenge fixtures use synthetic data and do not integrate with or bypass third-party anti-bot or CAPTCHA systems.
- Request content, full IP addresses, credentials, and browser fingerprints are not retained in application logs.
It is not a proxy, scraping gateway, credential collector, CAPTCHA solver, or anti-bot bypass service. Read the security and abuse model for the complete threat model.
CI validates the repository but does not deploy it. Production publication, Cloudflare resource changes, secrets, custom domains, and production smoke tests are explicit owner-run actions.
pnpm run deploy:dry-run
pnpm exec wrangler deployPlain pnpm exec wrangler deploy uses the production environment declared in wrangler.jsonc and requires the owner-managed CHALLENGE_SIGNING_KEY. Follow the deployment guide before publishing or rolling back.
Maintainer: Chris Butler