Embed the widget·续

Optional calls

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:

turnstile.reset(widgetId);

Get the response token

Retrieve the current response token at any time:

const responseToken = turnstile.getResponse(widgetId);

Remove a widget

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

turnstile.remove(widgetId);

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

Complete explicit rendering examples by use case

<details>

<summary>

Basic explicit implementation

</summary>

Examplehtml

<!DOCTYPE html>
<html>
    <head>
        <title>Explicit Rendering</title>
        <script
            src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"
            defer
        ></script>
    </head>
    <body>
        <form id="login-form">
            <input
                type="text"
                name="username"
                placeholder="Username"
                autocomplete="username"
            />
            <input
                type="password"
                name="password"
                placeholder="Password"
                autocomplete="current-password"
            />
            <div id="turnstile-widget"></div>
            <button type="submit">Login</button>
        </form>

<script>
            window.onload = function () {
                turnstile.render("#turnstile-widget", {
                    sitekey: "<YOUR-SITE-KEY>",
                    callback: function (token) {
                        console.log("Turnstile token:", token);
                        // Handle successful verification
                    },
                    "error-callback": function (errorCode) {
                        console.error("Turnstile error:", errorCode);
                    },
                });
            };
        </script>
    </body>
</html>

</details>

<details>

<summary>

Using onload callback

</summary>

Examplehtml

<script
    src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=onTurnstileLoad"
    defer
></script>
<div id="widget-container"></div>
<script>
    function onTurnstileLoad() {
        turnstile.render("#widget-container", {
            sitekey: "<YOUR-SITE-KEY>",
            theme: "light",
            callback: function (token) {
                console.log("Challenge completed:", token);
            },
        });
    }
</script>

</details>

<details>

<summary>

Advanced SPA implementation

</summary>

Examplehtml

<div id="dynamic-form-container"></div>

<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"></script>

<script>
    class TurnstileManager {
        constructor() {
            this.widgets = new Map();
        }
        createWidget(containerId, config) {
            // Wait for Turnstile to be ready
            turnstile.ready(() => {
                const widgetId = turnstile.render(containerId, {
                    sitekey: config.sitekey,
                    theme: config.theme || "auto",
                    size: config.size || "normal",
                    callback: (token) => {
                        console.log(`Widget ${widgetId} completed:`, token);
                        if (config.onSuccess) config.onSuccess(token, widgetId);
                    },
                    "error-callback": (error) => {
                        console.error(`Widget ${widgetId} error:`, error);
                        if (config.onError) config.onError(error, widgetId);
                    },
                });

this.widgets.set(containerId, widgetId);
                return widgetId;
            });
        }
        removeWidget(containerId) {
            const widgetId = this.widgets.get(containerId);
            if (widgetId) {
                turnstile.remove(widgetId);
                this.widgets.delete(containerId);
            }
        }
        resetWidget(containerId) {
            const widgetId = this.widgets.get(containerId);
            if (widgetId) {
                turnstile.reset(widgetId);
            }
        }
    }

// Usage
    const manager = new TurnstileManager();

// Create a widget when user clicks a button
    document.getElementById("show-form-btn").addEventListener("click", () => {
        document.getElementById("dynamic-form-container").innerHTML = `
        <form>
            <input type="email" placeholder="Email" />
            <div id="turnstile-widget"></div>
            <button type="submit">Submit</button>
        </form>
    `;
        manager.createWidget("#turnstile-widget", {
            sitekey: "<YOUR-SITE-KEY>",
            theme: "dark",
            onSuccess: (token) => {
                // Handle successful verification
                console.log("Form ready for submission");
            },
        });
    });
</script>

</details>

Widget lifecycle management

Explicit rendering provides full control over the widget lifecycle.

// Render a widget
const widgetId = turnstile.render("#container", {
    sitekey: "<YOUR-SITE-KEY>",
    callback: handleSuccess,
});

// Get the current token
const token = turnstile.getResponse(widgetId);

// Check if widget is expired
const isExpired = turnstile.isExpired(widgetId);

// Reset the widget (clears current state)
turnstile.reset(widgetId);

// Remove the widget completely
turnstile.remove(widgetId);

Execution mode

Control when challenges run with execution modes.

// Render widget but don't run challenge yet
const widgetId = turnstile.render("#container", {
    sitekey: "<YOUR-SITE-KEY>",
    execution: "execute", // Don't auto-execute
});

// Later, run the challenge when needed
turnstile.execute("#container");

Performance and user experience optimization

Cloudflare recommends that you execute the Turnstile script as early upon the visitor's page entry as possible, so that the verification is complete and the interaction is available once the visitor attempts an action on the page.


Configuration options

Both implicit and explicit rendering methods support the same configuration options. Refer to the table below for the most commonly used configurations.

Option Description Values
sitekey Your widget's sitekey Required string
theme Visual theme auto, light, dark
size Widget size normal, flexible, compact
callback Success callback Function
error-callback Error callback Function
execution When to run the challenge render, execute
appearance When the widget is visible always, execute, interaction-only

For a complete list of configuration options, refer to Widget configurations.


Testing

You can test your Turnstile widget on your webpage without triggering an actual Cloudflare Challenge by using a testing sitekey.

Refer to Testing for more information.


Limitations

Turnstile is designed to function only on pages using http:// or https:// URI schemes. Other protocols, such as file://, are not supported for embedding the widget.


Security requirements

  • Server-side validation is mandatory. It is critical to enforce Turnstile tokens with the Siteverify API. The Turnstile token could be invalid, expired, or already redeemed. Not verifying the token will leave major vulnerabilities in your implementation. You must call Siteverify to complete your Turnstile configuration. Otherwise, it is incomplete and will result in zeroes for token validation when viewing your metrics in Turnstile Analytics.
  • Tokens expire after 300 seconds (5 minutes). Each token can only be validated once. Expired or used tokens must be replaced with fresh challenges.

Was this helpful?

YesNo

On this page

Embed the widget·续 - 图1Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/#page","headline":"Embed the widget","description":"Embed a Turnstile widget on your website with JavaScript or HTML.","url":"https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/","inLanguage":"en","image":"https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/og.png?v=fa66c781356da0ea","dateModified":"2026-06-17","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"},"keywords":["JavaScript","SPA"]}


description: Configure widget appearance, language, and callback functions. title: Widget configurations image: https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/widget-configurations/og.png?v=200be8a9b419a2f9


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/turnstile/llms.txt
Use this file to discover all available pages before exploring further.