A straightforward bot defense for Cloudflare Pages

Shipping updates quickly while keeping automated abuse off your site is a constant tension. CAPTCHAs that force visitors to identify crosswalks and hydrants add friction, and they don’t always deliver the smooth experience users expect. Cloudflare Pages and Turnstile aim to remove that tradeoff, and the integration path is short enough to walk through end-to-end.

Pages provides git-based deployment, with unlimited requests, bandwidth, collaborators, and projects. Turnstile is Cloudflare’s CAPTCHA alternative; rather than a visual puzzle, it runs a hidden check that only prompts for interaction when it cannot confirm the visitor is human. Existing CAPTCHA users can migrate with minimal changes, per the Turnstile migration documentation.

This guide covers the practical flow: deploy a Pages site, embed the Turnstile widget, validate tokens server-side with Pages Functions, and read the Turnstile analytics that reveal bot pressure.

Project setup and deployment

Start from the Cloudflare dashboard under Workers & Pages and create a new Pages application linked to your git provider. Choose the repository for your project. Build settings are minimal:

  • Framework preset: None
  • Build command: npm install @cloudflare/pages-plugin-turnstile
  • Build output directory: public

Select “Save and Deploy” and the site goes live with a preview URL. Each deployment also generates a unique preview subdomain, which matters for widget configuration below.

Creating and configuring the Turnstile widget

In the Turnstile section of the dashboard, add the Pages site as a new widget. Only the primary domain is required; because Pages preview deployments use subdomains of that domain, Turnstile automatically covers them, so widget behavior is consistent across previews.

Three widget modes are available:

  • Managed: Cloudflare decides when extra validation is necessary. In clear-cut cases, the check happens invisibly; in ambiguous ones, the visitor must tick the checkbox. This is the recommended default and the mode used here.
  • Non-interactive: A visible widget that runs checks without user action, an approach suited to low-friction flows.
  • Invisible: The widget is not displayed at all and operates in the background.

There is also a pre-clearance setting that issues a clearance cookie, letting the site verify every request or once per session rather than per page load.

Once the widget is created, you receive two keys. The sitekey is public and used to initialize the widget on the client. The secret key is sensitive, hold onto it server-side.

Embedding the widget on the client

The widget can be embedded implicitly or explicitly. This example uses explicit embedding: inject the Turnstile JavaScript, then specify where the widget renders with a div and a turnstile.render call that references the same id. On the page, the widget sits directly above the Submit button.

Make sure the div id matches the id argument in the render invocation. After the script loads, the widget appears in place, ready for the form submit flow.

Server-side validation

Client-side rendering is only half the protection. The token that Turnstile issues, under the form field name cf-turnstile-response, needs to be verified against the /siteverify API. In the Pages Functions project, the submit handler at ./functions/api/submit.js performs this check.

The function sends the token to /siteverify and inspects the response. For demonstration purposes, the response is attached to the API reply so the outcome is visible during development. In production, that response should determine where the request flows next.

When Turnstile correctly identifies a human, the API returns success: true and interactive: false, meaning the check auto-passed and no user action was needed. If the visitor looks risky, the interaction flag flips, and the widget asks for a manual checkbox click. Managed mode handled both cases here without custom logic; other modes are available if your application has different requirements.

Reading the analytics

After Turnstile is in place, the dashboard’s Turnstile analytics page tracks two key metrics.

Visitor Solve Rate measures the percentage of visitors who completed the widget successfully. A prompt drop often indicates elevated bot traffic, since automated clients commonly fail the challenge.

API Solve Rate is the percentage of tokens that validated successfully against /siteverify. A significant decline points to bots failing to generate valid tokens.

Widget Traffic, meanwhile, shows the mix of challenges and outcomes hitting the site. Many interactive challenges suggest bots probing the property; a large number of unsolved challenges is a sign that the widget is filtering suspicious activity before it reaches the application.

With that, the site is live, widget is in place, tokens are checked server-side, and the analytics tell you whether to trust traffic or tune the setup. Both Pages and Turnstile are available free for all Cloudflare users through the dashboard.