---
title: Implement Turnstile using implicit and explicit rendering · Cloudflare Turnstile docs
description: This tutorial will explore the two primary methods of implementing Turnstile to your website via implicit or explicit rendering using a detailed explanation, a step by step implementation guide, and examples on how to help you protect your web application security while maintaining a good user experience.
lastUpdated: 2025-04-28T16:08:27.000Z
source_url:
  html: https://ngayerie-patch-15.preview.developers.cloudflare.com/turnstile/tutorials/implicit-vs-explicit-rendering/index.md
  md: https://ngayerie-patch-15.preview.developers.cloudflare.com/turnstile/tutorials/implicit-vs-explicit-rendering/
---

This tutorial will explore the two primary methods of implementing Turnstile to your website via **implicit or explicit rendering** using a detailed explanation, a step by step implementation guide, and examples on how to help you protect your web application security while maintaining a good user experience.

## Before you begin

* You must have a Cloudflare account.
* You must have a sitekey and secret key. You can obtain the sitekey and secret key from the Cloudflare dashboard after adding your zone to Turnstile.
* You must have basic knowledge of HTML and JavaScript. Familiarity with web development will help you follow along the tutorial.

## Implicit rendering

Implicit rendering automatically displays the Turnstile widget on your webpage without additional JavaScript code. This set up is ideal for static pages where you want the widget to load immediately when the page loads.

To set up implicit rendering:

1. **Include the Turnstile Script**: Add the Turnstile JavaScript API to your HTML file within the `<head>` section or just before the closing `</body>` tag.

```html
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
```

1. **Add the Turnstile widget to your HTML**: Insert a `div` element where you want the widget to appear.

```html
<div class="cf-turnstile" data-sitekey="yourSitekey" data-callback="javascriptCallback"></div>
```

Once a challenge has been solved, a token is passed to the success callback. This token must be validated against our [siteverify endpoint](https://developers.cloudflare.com/turnstile/get-started/server-side-validation/).

1. **Create Your Form**: Turnstile is often used to protect forms on websites such as login forms or contact forms. You can embed the widget within your `<form>` tag.

```html
  <form action="/submit" method="POST">
    <label for="name">Name:</label><br>
    <input type="text" id="name" name="name" required><br>
    <label for="email">Email:</label><br>
    <input type="email" id="email" name="email" required><br>
    <!-- Turnstile Widget -->
    <div class="cf-turnstile" data-sitekey="your-site-key"></div>
    <br>
    <button type="submit">Submit</button>
  </form>
```

An invisible input with the name `cf-turnstile-response` is added and will be sent to the server with the other fields.

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Implicit Rendering with Cloudflare Turnstile</title>
  <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body>
  <h1>Contact Us</h1>
  <form action="/submit" method="POST">
    <label for="name">Name:</label><br>
    <input type="text" id="name" name="name" required><br>
    <label for="email">Email:</label><br>
    <input type="email" id="email" name="email" required><br>
    <!-- Turnstile Widget -->
    <div class="cf-turnstile" data-sitekey="your-site-key"></div>
    <br>
    <button type="submit">Submit</button>
  </form>
</body>
</html>
```

## Explicit rendering

Explicit rendering helps you manually control when and where the Turnstile widget appears using JavaScript. This method is suitable for dynamic content, single-page applications(SPAs), or conditional rendering based on user interactions.

To set up explicit rendering:

1. **Include the Turnstile Script with `onload` callback**: From the previous example, modify the script tag to include an `onload` parameter.

```html
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback" defer></script>
```

1. **Create a container element**: Add a `<div>` with an ID or class where you want the widget to appear.

```html
<div id="my-turnstile"></div>
```

1. **Define the callback function**: In your code, define the `onloadTurnstileCallback` function.

```html
function onloadTurnstileCallback() {
    turnstile.render('#my-turnstile', {
        sitekey: '<YOUR_SITE_KEY>',
        callback: function(token) {
            console.log(`Challenge Success ${token}`);
        },
    });
}
```

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Explicit Rendering with Cloudflare Turnstile</title>
  <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback" defer></script>
</head>
<body>
  <h1>Register Account</h1>
  <form action="/register" method="POST" id="registration-form">
    <label for="username">Username:</label><br>
    <input type="text" id="username" name="username" required><br>
    <!-- Other form fields -->
    <!-- Turnstile Container -->
    <div id="my-turnstile"></div>
    <br>
    <button type="submit">Register</button>
  </form>


  <script>
    function onloadTurnstileCallback() {
    turnstile.render('#my-turnstile', {
        sitekey: '<YOUR_SITE_KEY>',
        callback: function(token) {
            console.log(`Challenge Success ${token}`);
        },
    });
  </script>
</body>
</html>
```

In the code above, The Turnstile script loads and calls `onTurnstileLoad` upon completion. `turnstile.render()` is used to manually render the widget in the specified container. The callback function handles the response token, which you can use for server-side verification.

If the invocation is successful, the function returns a `widgetId` (string). If the invocation is unsuccessful, the function returns undefined.

After rendering the Turnstile widget explicitly, you may need to interact with it based on your application's requirements. Refer to the sections below to manage the widget's state.

### Reset a widget

To reset the widget if the given widget timed out or expired, you can use the function:

```js
turnstile.reset(widgetId);
```

### Get the response token

Retrieve the current response token at any time:

```js
const responseToken = turnstile.getResponse(widgetId);
```

### Remove a widget

When a widget is no longer needed, it can be removed from the page using:

```js
turnstile.remove(widgetId)
```

This will not call any callback and will remove all related DOM elements.

## Server-side validation

Regardless of the rendering method, Turnstile tokens need to be verified using `siteverify` because the front-end widget creates a cryptographically secured token. To ensure that a token is not forged by an attacker or has not been consumed yet, it is necessary to check the validity of the token using Cloudflare's siteverify API.

The `siteverify` API will only validate a token once. If a token has already been checked, the siteverify API will yield an error on subsequent verification attempts indicating that a token has already been consumed.

```js
// This is the demo secret key. In prod, we recommend you store
// your secret key(s) safely.
const SECRET_KEY = '1x0000000000000000000000000000000AA';


async function handlePost(request) {
    const body = await request.formData();
    // Turnstile injects a token in "cf-turnstile-response".
    const token = body.get('cf-turnstile-response');
    const ip = request.headers.get('CF-Connecting-IP');


    // Validate the token by calling the "/siteverify" API.
    let formData = new FormData();
    formData.append('secret', SECRET_KEY);
    formData.append('response', token);
    formData.append('remoteip', ip);


    const result = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
        body: formData,
        method: 'POST',
    });


    const outcome = await result.json();
    if (!outcome.success) {
        return new Response('The provided Turnstile token was not valid! \n' + JSON.stringify(outcome));
    }
    // The Turnstile token was successfuly validated. Proceed with your application logic.
    // Validate login, redirect user, etc.
    // For this demo, we just echo the "/siteverify" response:
    return new Response('Turnstile token successfuly validated. \n' + JSON.stringify(outcome));
}


export default {
    async fetch(request) {
        if (request.method === 'POST') {
            return await handlePost(request);
        }


        const url = new URL(request.url);
        let body = implicitRenderHtml;
        if (url.pathname === '/explicit') {
            body = explicitRenderHtml;
        }


        return new Response(body, {
            headers: {
                'Content-Type': 'text/html',
            },
        });
    },
};
```

Prevent potential errors when accessing request.body

The body of a [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) can only be accessed once. If you previously used `request.formData()` in the same request, you may encounter a TypeError when attempting to access `request.body`.

To avoid errors, create a clone of the Request object with `request.clone()` for each subsequent attempt to access a Request's body. Keep in mind that Workers have a [memory limit of 128 MB per Worker](https://developers.cloudflare.com/workers/platform/limits#worker-limits) and loading particularly large files into a Worker's memory multiple times may reach this limit. To ensure memory usage does not reach this limit, consider using [Streams](https://developers.cloudflare.com/workers/runtime-apis/streams/).

## Choose between implicit and explicit rendering

Choosing the appropriate rendering method for Turnstile is important and effectively helps you to add it to your website while ensuring optimal performance and user experience. Both implicit and explicit rendering have their own advantages and are suited to different types of web applications. Refer to the table below that highlights the ideal use case for each of these rendering methods:

| **Feature** | **Implicit rendering** | **Explicit rendering** |
| - | - | - |
| **Ease of setup** | Simple, minimal code | Requires additional JavaScript |
| **Control over timing** | Renders automatically on page load | Full control over rendering timing |
| **Use cases** | Static content | Dynamic or interactive content |
| **Customization** | Limited to HTML attributes | Extensive via JavaScript API |

## Best practices

1. Always verify the Turnstile response token on your server.
2. Ensure your implementation is accessible to all users.
3. Test your integration across different browsers and devices.
4. Load the Turnstile API script asynchronously to prevent blocking.

Implementing Turnstile into your website helps improve the security of your website without compromising user experience. By understanding and implementing implicit or explicit rendering, you can choose the method that best fits your website's architecture and user interaction patterns.

* Implicit rendering is ideal for static pages with minimal JavaScript.
* Explicit rendering offers greater control for dynamic and interactive applications.

Remember to perform server-side validation of the response token to complete the authentication process securely.

## Additional resources

* [Server-side validation](https://developers.cloudflare.com/turnstile/get-started/server-side-validation/): A guide on how to implement server-side validation to ensure that only valid, human-generated responses are accepted by your application.
* [Turnstile Analytics](https://developers.cloudflare.com/turnstile/turnstile-analytics/): A guide on how to access and interpret Turnstile Analytics data, allowing you to monitor key metrics, access the number of challenges issued, and evaluate the [challenge solve rate (CSR)](https://developers.cloudflare.com/fundamentals/security/cloudflare-challenges/challenge-solve-rate/).
* [Turnstile API Reference](https://developers.cloudflare.com/api/resources/turnstile/subresources/widgets/methods/list/): Comprehensive documentation for the Turnstile API, providing detailed information on API operations for managing Turnstile widgets, including how to list, create, and update widgets via API calls.
