Move from Cloudflare Turnstile to Wicket
Change the script address, the widget's class name and the verify address to move a site from Turnstile to Wicket, and switch without a gap.
Wicket speaks Cloudflare Turnstile's protocol, so a site that uses Turnstile moves by changing three things: the script address, the class name on the widget's container and the verify address. The form field and the JavaScript global change name too. The options, the callbacks and the answer your server reads keep their shape. This page lists each change, what stays the same, and an order to switch in that leaves no form unprotected.
Before you begin
Section titled Before you begin- Add a Wicket widget for the site, with the same hostnames as the Turnstile widget and the mode that matches (Add a widget). Turnstile's Managed, Non-Interactive and Invisible widgets match Wicket's Managed, Non-interactive and Invisible.
- Copy the secret key when the page shows it. We show it once, and a lost key is replaced by rotating it (Rotate the secret key).
- Find where your site loads the Turnstile script and where your server verifies a token. Search your code for
turnstileandcf-turnstile.
The changes
Section titled The changes| What | Turnstile | Wicket |
|---|---|---|
| Script address | https://challenges.cloudflare.com/turnstile/v0/api.js |
https://wicket.coritan.com/v1/api.js |
| Class on the container | cf-turnstile |
wicket-widget |
| Verify address | https://challenges.cloudflare.com/turnstile/v0/siteverify |
https://api.coritan.com/api/v1/wicket/siteverify |
| Form field | cf-turnstile-response |
wicket-response |
| JavaScript global | window.turnstile |
window.wicket |
| Site key | Starts with 0x |
Starts with wk_ |
| Secret key | Starts with 0x |
Starts with wks_ |
The Install tab of your widget shows the exact script address and verify address for the widget (Install a widget).
Switch without a gap
Section titled Switch without a gapA visitor who loaded a page before you changed it still holds a Turnstile token for as long as the page stays open, and a cache may keep serving the old page. Your server therefore verifies both kinds of token for an hour.
Allow Wicket in your Content-Security-Policy, if your site sends one. Add
https://wicket.coritan.comtoscript-srcandframe-src, and keep Cloudflare's entries (Allow Wicket in a Content Security Policy).Change your server so it reads both fields. It verifies
wicket-responseat the Wicket address with the Wicket secret key, andcf-turnstile-responseat Turnstile's address with the Turnstile secret key:JavaScriptconst wicketToken = form["wicket-response"]; const turnstileToken = form["cf-turnstile-response"]; const passed = wicketToken ? await verifyWithWicket(wicketToken) : await verifyWithTurnstile(turnstileToken);verifyWithWicketis the call in Verify a token on your server, and it posts tohttps://api.coritan.com/api/v1/wicket/siteverify:Verify a Wicket tokencurl https://api.coritan.com/api/v1/wicket/siteverify \ --data-urlencode "secret=$WICKET_SECRET_KEY" \ --data-urlencode "response=$TOKEN"Deploy the server, and check that forms that still use Turnstile are accepted.
Change the page. Replace the script address, change the class from
cf-turnstiletowicket-widget, and put the Wicket site key indata-sitekey:HTML<script src="https://wicket.coritan.com/v1/api.js" async defer></script> <div class="wicket-widget" data-sitekey="wk_..." style="min-height: 65px"></div>The
min-heightkeeps the page from moving when the widget appears, and is140pxfor a Compact widget. When your Content-Security-Policy forbids inline styles, put it in a stylesheet instead (Reserve the widget's height).If your own script calls
turnstile.render,turnstile.resetor any other function, callwicket.render,wicket.resetand the others instead (Widget options).Load the page and submit the form. The widget should show Success, and the verify call should answer
"success": true.Wait an hour. Then remove the Turnstile verify call, the Turnstile secret key and the Cloudflare entries in your Content-Security-Policy.
To test before step 4 goes live, use a test key on a development copy of the page. Turnstile's own test keys do not work with Wicket.
Tip
To keep your server reading cf-turnstile-response, set data-response-field-name="cf-turnstile-response" on the container. You still change the verify address. During the hour of overlap the two kinds of token would then arrive in the same field and your server could not tell them apart, so use wicket-response until Turnstile is gone.
What stays the same
Section titled What stays the same| What | On Wicket |
|---|---|
Widget options and data- attributes |
The same names and defaults, such as theme, size, language, action, cdata, appearance, execution, retry, refresh-expired and response-field-name. Wicket adds a few of its own (Widget options). |
| Callbacks | callback, error-callback, expired-callback, timeout-callback, before-interactive-callback, after-interactive-callback and unsupported-callback. |
| Functions | render, execute, reset, remove, getResponse, isExpired and ready. |
| The script's parameters | render=explicit and onload. |
| The verify call's fields | secret, response, remoteip and idempotency_key, sent form-encoded, as multipart form data or as JSON. |
| The verify answer | success, challenge_ts, hostname, error-codes, action, cdata and metadata. |
| The error codes of the verify call | missing-input-secret, invalid-input-secret, missing-input-response, invalid-input-response, bad-request, timeout-or-duplicate and internal-error. |
| The token | It works once, for 300 seconds, and is at most 2048 characters. |
idempotency_key |
A repeat of a call with the same key returns the first answer (Repeat a call safely). |
| Hostnames | A hostname covers itself and every name under it, so example.com covers www.example.com. |
What differs
Section titled What differs| What | On Wicket |
|---|---|
| The secret key | We show it once, when you add the widget and when you rotate it, and keep only a fingerprint. Copy it then. |
| Test keys | Wicket has its own test site keys and secret keys, with their own names (Test keys). |
The codes your error-callback receives |
Words such as network and failed, listed in Widget options. |
metadata in the verify answer |
interactive and event. Store event to report a check later (Verify a token on your server). |
| The verify call's budget | A widget may make 6000 calls a minute, and a call past it answers HTTP 429 with rate-limited (Limits). |
| Plan limits | Your plan sets how many widgets you have and how many hostnames each lists (Limits). |
Result
Section titled ResultVisitors pass the Wicket widget, and your server accepts forms on the strength of wicket-response alone. The Analytics tab of the widget counts the challenges, and Valid under Tokens verified rises with Passed (Read a widget's analytics).
Troubleshooting
Section titled Troubleshooting- The widget shows This site's check is not set up for this page with
unknown_sitekey - The page still has the Turnstile site key. Put the widget's Wicket site key, which starts with
wk_, indata-sitekey. - The widget does not appear
- The container may still have the class
cf-turnstile, or your Content-Security-Policy may blockhttps://wicket.coritan.com. Troubleshoot Wicket lists the causes. - The verify call answers
invalid-input-secret - The call sends the Turnstile secret key to the Wicket address. Send the widget's secret key, which starts with
wks_. - The verify call answers
invalid-input-response - The call sends a Turnstile token to the Wicket address. Read the token from
wicket-responsefor Wicket and fromcf-turnstile-responsefor Turnstile. - The console says
turnstile is not defined - A script on your page still calls
turnstile. Callwicketinstead.
Related
Section titled RelatedNext steps
Section titled Next steps- Read a widget's analytics to see the challenges and verified tokens after the switch.
- Change a widget's settings to add hostnames or rotate the secret key.
- Check the limits of your plan for widgets and hostnames.