# Bot protection

Bot protection stops scripts from using a public form, such as a sign-up
or a demo request. The browser shows a challenge widget, and your app
checks the token it gives. `bot_check` is a capability with one
operation, checking a token: pass or fail. A package fills it, such as
Cloudflare Turnstile, hCaptcha or reCAPTCHA, and you name its connection
in `application { }`. A route, or a generated feature, asks for the
check with `bot_check: true`:

```jadpo
// app.jadpo
application {
    connections: {
        turnstile: {
            package: Turnstile.v0
            credential: config.turnstile_secret
        }
    }
    bot_check: {
        connection: turnstile
    }
}

// domains/sales/routes/demo_requests.jadpo
POST / {
    authentication: RouteAuthentication.none
    input: RequestDemo
    status: SuccessStatus.no_content
    run: request_demo(input)
    bot_check: true
}
```

- **Jadpo's own public endpoints are checked too,** the magic-link and
  privacy requests, whenever `bot_check:` names a connection.
- **The frontend shows the widget.** The token travels in the
  `X-Bot-Check` header, never in the route's input, and is checked
  before the action runs, within the request's deadline.
- **A failed check** is the built-in failure `bot_check_failed` (403),
  worded from translations like every failure
  ([Failures for client apps](failures-for-client-apps.md)).
- **reCAPTCHA's score** gets a threshold setting on its connection.
- **An unreachable provider refuses the request,** so the check fails
  closed. Letting requests through while it is down needs an
  [acceptance](acceptances.md), listed in the
  approval report.
- **Development and tests pass every check** through a local driver,
  and a test can script `bot_check_failed`
  ([Fakes for integrations](fakes-for-integrations.md)).
- `bot_check: true` with no `bot_check:` connection is a compile error
  naming the setting to add.
