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
{"@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
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.
Docs