Skip to content

Captcha

captcha.turnstile() and captcha.recaptcha() protect public application routes with managed CAPTCHA verification. Layeron keeps the user-facing API route-shaped while compiling the security behavior into the normal platform pipeline.

Use Captcha when a public route needs a human verification step before business logic runs. Common places include signup, contact forms, checkout steps, password reset, invitation acceptance, and other routes where a bot should be stopped at the Gateway boundary.

Captcha can:

  • Create and maintain Cloudflare Turnstile widgets during deploy.
  • Adopt Google reCAPTCHA widgets with explicit sitekeys and Layeron secret references.
  • Inject provider secrets into the Gateway Worker.
  • Expose public sitekeys for client rendering.
  • Verify tokens before route handlers run.
  • Support manual verification for custom control flow.
  • Adopt an existing Turnstile widget through an explicit sitekey and secret reference.
  • Return stable failure responses.
  • Keep widget resources, bindings, and secret usage visible in deployment state.

Captcha is an ingress capability. The Gateway receives the request, extracts the provider token from the configured source, verifies it with the provider Siteverify API, and continues to the route handler only after verification succeeds.

Terminal window
route declaration
-> captcha guard metadata
-> provider widget or adopted sitekey
-> Gateway Worker bindings
-> Gateway runtime verification
-> deployment state

Managed Captcha instances use Cloudflare Turnstile resources in the user’s Cloudflare account. Adopted instances, including Google reCAPTCHA, keep the existing widget and use a Layeron secret reference for the provider secret.

Use automatic verification for routes where every request must pass Captcha before the handler runs:

Terminal window
app.post("/signup", { use: [signupCaptcha] }, async () => {
return { ok: true }
})

Use manual verification when the handler owns the request flow, response shape, or token location:

Terminal window
app.use(signupCaptcha)
app.post("/api/signup", async (request) => {
const body = await request.json()
const result = await signupCaptcha.verifyToken(body.captchaToken, {
request,
hostname: "app.example.com",
action: "signup",
})
if (!result.ok) {
return result.response()
}
return { ok: true }
})

Both paths use the same Gateway-bound provider secret and provider Siteverify endpoint. Automatic verification returns the configured failure response immediately. Manual verification returns a structured result so the handler can choose the response.

  • Set domains for every production widget so hostname validation uses an explicit allowlist.
  • Set action for each user flow and keep it aligned with the client data-action value.
  • Set minScore for reCAPTCHA v3 flows that should reject low-confidence traffic.
  • Use separate Captcha instances for flows with different risk or abuse profiles.
  • Keep adopted provider secrets in Layeron secret references when adopting an existing widget.
  • Return a stable JSON failure body through failure so clients can handle verification errors consistently.
  • Restrict dev: { mode: "bypass" } to local or test environments.
  • Get started: Choose a provider, protect a route, submit client tokens, and run manual verification.
  • Cloudflare Turnstile: Create a managed widget, adopt an existing widget, and configure production behavior.
  • Google reCAPTCHA: Verify reCAPTCHA tokens with a Layeron secret reference and score checks.
  • API reference: Review provider options, token sources, failure behavior, and verification results.