type: decision
status: active
timestamp: 2026-06-20
tags: [decisions, security, captcha, turnstile, hcaptcha]

Captcha — Turnstile primary + hCaptcha fallback (both, regional auto-detect)

Turnstile primary, hCaptcha fallback. Single Captcha component

Captcha — Turnstile primary + hCaptcha fallback (both, regional auto-detect)

Decision

Every public POST surface across *.oriz.in (contact forms, sign-up, comment, support) goes through one captcha component shipped from : <Captcha>. The component:

  1. Probes challenges.cloudflare.com on mount.
  2. If reachable ? renders Cloudflare Turnstile (the primary).
  3. If blocked (corporate proxy / region / ad-blocker / Cloudflare-edge incident) ? renders hCaptcha (the fallback).
  4. Tags the issued token with its provider so the Worker dispatches to the correct verify endpoint.

Both are free, no card. Turnstile carries the bulk; hCaptcha is the documented swap target the kit reaches for automatically.

Why

Implications

Architecture

CSP

The family’s _headers preset must allow:

script-src ... https://challenges.cloudflare.com https://*.hcaptcha.com
connect-src ... https://challenges.cloudflare.com https://*.hcaptcha.com
frame-src https://challenges.cloudflare.com https://*.hcaptcha.com

This is the CSP delta this decision introduces; the kit ships the extended directive by default.

Coexistence with App Check + reCAPTCHA Enterprise

App Check + reCAPTCHA Enterprise continue to gate Firestore writes (provider-agnostic, server-side attestation). The Turnstile + hCaptcha pair gates the public Worker API — different attack surfaces, different providers, no overlap. Bot defense remains layered.

What we don’t do

Cross-refs


Edit on GitHub · Back to index