Cloudflare Turnstile checks hosted authentication flows before Authdog issues a session or a one-time code. Configure it per environment. If Google reCAPTCHA is also enabled for the same flow, reCAPTCHA is the one that runs.

## Create the widget

1. Open the [Cloudflare Turnstile dashboard](https://dash.cloudflare.com/?to=/:account/turnstile).
2. Create a widget and add every domain that serves your Authdog pages, including any [custom domain](/docs/custom-domains).
3. Pick a mode: **Managed**, **Non-interactive**, or **Invisible**.
4. Copy the site key and the secret key.

## Enable the add-on

In the [Authdog console](https://console.authdog.com):

1. Select the project and environment.
2. Open **Authentication > Add-ons**.
3. Select **Cloudflare Turnstile**.
4. Set the widget mode to the same mode you created in Cloudflare.
5. Enter the **site key** and the **secret key**.
6. Select the flows to protect. Selecting none protects all of them.
7. Enable the add-on and save.

| Widget mode | What the user sees | Which flows |
| --- | --- | --- |
| **Managed** | Adaptive challenge. A checkbox only when Cloudflare asks for one | Sign-in, sign-up, waitlist, password reset |
| **Non-interactive** | A spinner. No click | Same as managed |
| **Invisible** | Nothing | Those four, plus magic link, one-time code, and MFA verification |

Magic link, one-time code, and MFA verification have no room for a checkbox. They need **Invisible**. A managed widget on those flows does nothing, and the request continues without a token.

A mode mismatch makes Cloudflare reject the token. The check then fails closed and the user sees a verification error.

## Roll out

1. Configure development first and complete a real sign-up.
2. Start with sign-up, waitlist, and password reset.
3. Add sign-in, then magic link and one-time codes, once real traffic looks healthy.
4. Repeat in production with production keys. Keys do not copy between environments.

Authdog verifies every token at Cloudflare's `siteverify` endpoint. A missing or invalid token fails closed. A Cloudflare outage on `siteverify` itself fails open, so an outage does not lock the environment.

## Related

| Read | To learn how to |
| --- | --- |
| [Bot protection](/docs/bot-protection) | Actions, fail-closed rules, and rollout order |
| [Custom domains](/docs/custom-domains) | Hostnames that must be on the widget |
| [Marketplace](/marketplace/turnstile) | The listing for this integration |
