A reverse-captcha gateway for the agentic web.
Cloudflare protects sites from bots. OpenBouncer protects agent-only spaces from humans — and routes verified agents to the sites that want them.
- Public preview live at openbouncer.com
- npm:
@openbouncer/gate@preview - Community token
$OBlive on pump.fun — creator rewards fund the build, holders unlock premium tiers (see#holders) - v0.1.draft · MIT licensed · built in the open
OpenBouncer is two things in one shape:
-
A verification gateway that sits in front of endpoints which only software should be calling. It exposes a single
POST /api/verifythat evaluates a layered set of proofs and returnspassordenyin under 40 ms. -
A public registry that agents query as a discovery layer. Sites adopting OpenBouncer publish a
.well-known/openbouncer.jsondocument; agents read it to learn how to enter.
Why? The agentic web (MCP, Computer Use, Operator, Gemini Agents) is shipping fast but there is no standard layer for "this is an agent talking, not a human." OpenBouncer plays the same network-effect game as Cloudflare did for bot defense — flipped.
L1 prompt-following challenge — agent extracted the page's hidden nonce
L2 sub-200 ms latency window — request arrived faster than humans can
L3 parallel reasoning proof — sub-second multi-task challenge (v0.2)
L4 provider attestation — signed token from a recognized runtime
(Anthropic, OpenAI, Google)
A request that matches any layer passes. The marketing site demo ships L1 and L4; L2/L3 land with the v0.2 spec.
The public-preview gateway accepts a static demo nonce so anyone can curl-test the flow.
# pass — agent payload
curl -X POST https://openbouncer.com/api/verify \
-H 'Content-Type: application/json' \
-H 'X-Agent-Provider: anthropic' \
-d '{"nonce":"ob_demo_a8f3c9e2","attest":"<signed-provider-token>"}'
# deny — browser-style bare click
curl -X POST https://openbouncer.com/api/verify \
-H 'Content-Type: application/json' \
-d '{}'Discovery:
curl https://openbouncer.com/.well-known/openbouncer.jsonFresh per-session nonce for real integrations:
curl https://openbouncer.com/api/challengebun add @openbouncer/gate@preview
# or: npm install @openbouncer/gate@previewimport { OpenBouncerGate } from '@openbouncer/gate'
export default function ProtectedPage({ nonce }: { nonce: string }) {
return (
<OpenBouncerGate nonce={nonce} provider="anthropic">
{/* rendered only for verified agents */}
<YourAgentOnlyContent />
</OpenBouncerGate>
)
}Three lines. Headless: zero CSS dependency, inline-styled defaults, ESM +
CJS + .d.ts, ~24 KB unpacked. See
packages/gate/README.md for the full API
reference.
For non-React runtimes (Bun, Node, Workers, CLIs), import the pure async primitive:
import { verify } from '@openbouncer/gate'
const r = await verify({
nonce: 'ob_demo_a8f3c9e2',
provider: 'anthropic',
attest: '<signed-provider-token>',
})
// → { ok: true, decision: "pass", matched_layers: [1,4], token: "ob_..." }.
├── server/ Fetch-API style handlers (Bun + Vite plugin)
│ ├── index.ts standalone Bun server (production)
│ └── lib/
│ ├── decision.ts layered evaluation (L1, L2, L3, L4)
│ ├── verify.ts POST /api/verify
│ ├── challenge.ts GET /api/challenge
│ ├── well-known.ts GET /.well-known/openbouncer.json
│ ├── router.ts tiny shared route table
│ ├── rate-limit.ts in-memory per-IP token bucket
│ ├── token.ts opaque pass-token envelope (v0.1)
│ └── json.ts cors + security-header helper
├── src/
│ ├── components/
│ │ ├── OpenBouncerGate.tsx the widget — both 3rd-party gate + demo
│ │ ├── Hero.tsx + the rest of the marketing site
│ │ └── ...
│ ├── App.tsx
│ └── index.css
├── vite-plugin-openbouncer.ts dev plugin wiring the same handlers
├── vite.config.ts
└── package.json
bun install
bun run dev # vite + api on the same origin (http://localhost:5173)
bun run server # bun-serve the api standalone (defaults to :3001)
bun run typecheck # tsc -b
bun run build # vite buildOpenBouncer ships as a single Cloudflare Pages project: the Vite-built
static site under dist/ plus a functions/[[path]].ts catchall that
runs the same Fetch-API handlers used in dev and in the standalone Bun
server. One origin, no CORS dance, edge-deployed globally.
bunx wrangler login # one-time, opens browser
bun run deploy # bun run build + wrangler pages deploybun run deploy is sugar for:
wrangler pages deploy dist --project-name=openbouncerTo bind the custom domain (after the first deploy creates the project):
bunx wrangler pages domain add openbouncer.com --project-name=openbouncerCloudflare provisions the SSL cert automatically once DNS is verified.
Subsequent deploys push to the same project — set up the GitHub
integration in the Cloudflare Pages dashboard for auto-deploy on push to
main.
| Surface | State |
|---|---|
| Reverse-captcha widget | ✅ live on openbouncer.com |
/api/verify (L1 + L4 stub) |
✅ live |
/api/challenge (fresh nonce) |
✅ live |
/.well-known/openbouncer.json |
✅ live |
@openbouncer/gate npm package |
✅ published (preview tag) |
| Per-session nonce store | ⏳ v0.2 |
| Ed25519-signed pass tokens | ⏳ v0.2 |
| Real provider-attestation verification | ⏳ v0.2 |
Stable @openbouncer/gate on the latest tag |
⏳ v0.2 |
| Public registry UI | ⏳ v0.2 |
| MCP server for agent discovery | ⏳ v0.2 |
MIT.