What you’ll need
- A deployed Esper API that your Worker can reach.
- An Esper tenant for the application you want to protect.
- An Esper API key for that tenant, stored as a Worker secret.
- At least one mitigation and policy in Esper.
- If you want managed challenge redirects, a challenge mitigation with a default return URL template already configured.
- A decision about failure behavior if Esper is unavailable: fail open or fail closed.
Recipe SourceThe Worker below is the customer-facing version of the
recipes/cloudflare
recipe. You do not need access to the Esper repository to deploy it.What this integration does
The Worker can verify Esper challenge proofs at the edge as a latency optimization. For normal requests, it captures Cloudflare request context, sends one synchronous runtime decision request to Esper, and then immediately applies the returnedallow, challenge, or block action before forwarding
traffic. Esper also verifies proof query parameters and pass cookies inside
/runtime/mitigation, so forwarding request query parameters and cookies is
the correctness requirement.
Canonical Worker flow:
Challenge proof handling
Esper-managed challenges return visitors to the protected URL with anesper_challenge_proof query parameter. The Worker may verify that token with
POST /api/v1/challenge/proof/verify, store the proof in a short-lived
first-party pass cookie, remove the query parameter, and redirect the browser
to the cleaned URL.
This keeps the origin and browser URL from retaining the challenge proof token.
The pass cookie lets follow-up requests during the proof TTL skip another
runtime challenge. If the Worker forwards the proof query parameter or proof
cookie in the /runtime/mitigation request context, Esper Cloud validates it
before policy evaluation and returns allow without writing another challenge
decision or challenge session.
Runtime decision request
For normal requests, the Worker sends onePOST /api/v1/runtime/mitigation
request. The payload preserves the method, path, selected Cloudflare headers,
query parameters, cookies, route parameters, and the original return_url.
The fields.probe value intentionally keeps the runtime payload non-empty
while your tenant-specific request extraction and policy logic reads the request
context.
Environment variables
Required:ESPER_API_KEY
https://api.esperr.com/api/v1 directly. Fork the recipe only
if you need to point at a non-production Esper API host.
Forwarding model
For the standard setup, attach the Worker to a route on the customer’s existing Cloudflare-proxied hostname, such as:allow, the Worker calls fetch(request). Cloudflare then
forwards the original request to the hostname’s configured origin. The customer
does not need to provide their Vercel origin or restate any upstream URL.
Use a custom reverse-proxy fork only for the less common deployment where the
Worker receives traffic for one hostname and must forward allowed requests to a
different origin hostname.
Create the Worker project
Create a new Cloudflare Worker project with Cloudflare’s setup tool:package.json, and install
dependencies. Do not deploy from the setup wizard; deploy only after adding the
Esper Worker code and ESPER_API_KEY secret.
Add the Esper Worker code
Replace the generated Worker entry file, usuallysrc/index.ts, with the
Esper Cloudflare Worker code from this guide.
Deploy
wrangler secret put ESPER_API_KEY prompts
for the secret value.
Bind the Worker to your site
After settingESPER_API_KEY, add a route to the generated Wrangler config.
For current Cloudflare Worker projects, this file is usually wrangler.jsonc.
For example, to run Esper on all requests to arbi.gg, add routes as a
top-level field:
What the Worker applies
allow: forward the request upstream.challenge: redirect to the Esper-managed challenge URL returned by/api/v1/runtime/mitigation.block: return the Esper block response from the inline/api/v1/runtime/mitigationdecision.
Challenge redirects
Sendreturn_url: request.url with each runtime mitigation request. This is the
original URL the visitor requested, and Esper stores it on the challenge session
so a successful challenge can return the visitor to the protected page. The
mitigation’s default return URL template is only a fallback when the integration
does not provide a per-request return_url.
Customer ExperienceThe customer should not have to call Beacon, mitigation, and challenge APIs
separately. The Worker should hide that complexity and make Esper feel like one
deployed protection layer.