Add Wicket to your site
Put the Wicket script and widget on a page, send the token with the form, check it on your server, and cover explicit rendering, several widgets and apps.
Wicket has two halves. A script on your page draws the widget and puts a token in your form, and your server asks Wicket whether the token is real. This page covers the page half and points to the server half. If you used Cloudflare Turnstile before, you change three things: the script address, the class name cf-turnstile to wicket-widget, and the verify address (Move from Cloudflare Turnstile to Wicket).
Before you begin
Section titled Before you begin- You need a widget, with its site key (it starts with
wk_) and its secret key (it starts withwks_). In the dashboard, go to Security and on the Wicket card select Open Wicket. The Wicket overview says what a widget is, and Manage widgets with the API adds one from your own tools. - The widget must list the hostname of the page that shows it. A hostname covers every name under it, so
example.comcoverswww.example.com. - Serve the page over HTTPS. The widget needs a browser feature that browsers give a frame only when the page that holds it is served over HTTPS, or from
localhost. On a plainhttp://page the widget shows This browser cannot run the check. - To try the page before you use a real widget, use a test key. It works on any hostname,
localhostincluded.
Add the widget to a page
Section titled Add the widget to a pageAdd the script to the page once. It loads with
async defer, so it does not hold the page up:HTML<script src="https://wicket.coritan.com/v1/api.js" async defer></script>Add a
divwith the classwicket-widgetinside the form, where the check should appear. Itsdata-sitekeyis the widget's site key:HTML<form action="/signup" method="post"> <label for="email">Email address</label> <input id="email" name="email" type="email"> <div class="wicket-widget" data-sitekey="wk_..." style="min-height: 65px"></div> <button type="submit">Create account</button> </form>Load the page. The script draws one widget in every element with the class
wicket-widget.
The min-height keeps the page from moving when the widget appears. The script runs after the page has drawn, so without it the form jumps down by the widget's height. Use 65px for the Normal and Flexible sizes and 140px for Compact (Reserve the widget's height). A container for an Invisible widget takes no room: see Invisible widgets.
Reserve the widget's height
Section titled Reserve the widget's heightA widget is 65px high at the Normal and Flexible sizes and 140px high at the Compact size, whether the size comes from data-size, from wicket.render or from the widget's Appearance setting. Reserve the height of the size the widget uses.
The style attribute above is an inline style. When your Content-Security-Policy forbids inline styles (it has style-src without 'unsafe-inline'), the browser ignores the attribute and the page moves. Put the rule in a stylesheet your policy allows instead, and leave the style attribute off the container:
.wicket-widget {
min-height: 65px;
}
.wicket-widget[data-size="compact"] {
min-height: 140px;
}
The second rule needs data-size="compact" on the container. When you set the size in wicket.render or in the widget's settings, give the container a class of your own and size that class:
.signup-check {
min-height: 140px;
}
Options
Section titled OptionsPut an option on the div as a data- attribute: data-theme="dark", data-size="compact", data-action="signup". Widget options lists every option, its values and its default, and the callbacks the widget calls.
Send the token with the form
Section titled Send the token with the formWhen the visitor passes, the script adds a hidden field named wicket-response to the widget's container and puts the token in it. Because the container is inside the form, the browser sends the token with the form like any other field.
- To send the form from your own JavaScript, read the token with
wicket.getResponse(), or pass acallbackto receive it as soon as it exists. - To use another field name, set
data-response-field-name. - A token works once and for 300 seconds. After you send a form, call
wicket.reset()to get a new token for the next one. When a visitor takes longer than 300 seconds the widget renews the token on its own.
Check the token on your server
Section titled Check the token on your serverNever accept the form on the strength of the widget alone, because a script can send a form without loading the widget. Your server posts the token and your secret key to the verify address, and refuses the form when the answer's success is false.
Verify a token on your server has the call, examples in five languages, the answer and its error codes.
Draw the widget yourself
Section titled Draw the widget yourselfUse explicit rendering when the page builds its forms in JavaScript, or when you want to choose when the widget appears.
Add
?render=explicitto the script address. Add&onload=onWicketLoadto be called when the script is ready:HTML<script src="https://wicket.coritan.com/v1/api.js?render=explicit&onload=onWicketLoad" async defer></script>Define the function the script calls, and render a widget in an element or a selector:
JavaScriptfunction onWicketLoad() { const id = wicket.render("#signup-check", { sitekey: "wk_...", callback: (token) => console.log("Passed", token), }); }wicket.renderreturns the widget's id. The options you pass override the container'sdata-attributes.
Put several widgets on one page
Section titled Put several widgets on one pageEvery container with the class wicket-widget, and every call to wicket.render, gets its own frame, its own token and its own hidden field.
- Give each widget in the same form its own
data-response-field-name. Two fields with the same name reach your server as two values, and most servers read only one of them. - Pass the id that
wicket.renderreturned, the container element or a selector towicket.getResponse,wicket.resetandwicket.remove. With no argument they act on the first widget on the page. - Widgets on one page can use different site keys, themes and sizes.
Use Wicket in a single-page app
Section titled Use Wicket in a single-page appA single-page app builds and removes forms without loading a new page. Load the script once, in your page's index.html, with ?render=explicit&onload=onWicketLoad. Then draw the widget when the form appears and remove it when the form goes away:
// Resolves once the script is ready, whether it has loaded yet or not.
function wicketReady() {
return new Promise((resolve) => {
if (window.wicket) window.wicket.ready(resolve);
else window.onWicketLoad = resolve;
});
}
// React, in a component that holds the form
useEffect(() => {
let id;
let gone = false;
wicketReady().then(() => {
if (gone) return;
id = window.wicket.render(containerRef.current, {
sitekey: "wk_...",
callback: setToken,
"expired-callback": () => setToken(null),
});
});
return () => {
gone = true;
if (id !== undefined) window.wicket.remove(id);
};
}, []);
- Call
wicket.remove(id)when the form is removed, so the frame and its timers go with it. - Call
wicket.reset(id)after each submit that fails, so the visitor gets a new token. A token that your server has verified once cannot be used again. - Keep the token in your app's state with
callbackandexpired-callback, or read it withwicket.getResponse(id)when you submit. - Give the container its
min-heightin your stylesheet (Reserve the widget's height), so the page does not move when a route draws the widget.
Invisible widgets
Section titled Invisible widgetsAn Invisible widget draws nothing. The script cannot tell that a widget is invisible until its frame has loaded, so a widget left to the default appearance first holds the room of a visible one, and then gives it back, which moves the page. Say it on the container instead, and do not give it a min-height:
<div id="check" class="wicket-widget" data-sitekey="wk_..." data-appearance="interaction-only" data-execution="execute"></div>
With data-execution="execute" the check starts when your code calls wicket.execute("#check"), for example when the visitor presses the submit button. Widget modes explains the three modes, and the script writes one line to the browser's console when it finds an Invisible widget that was not marked.
Allow Wicket in a Content Security Policy
Section titled Allow Wicket in a Content Security PolicyIf your site sends a Content-Security-Policy, allow the script and the frame the script draws. Add Wicket's address to script-src and frame-src:
script-src https://wicket.coritan.com;
frame-src https://wicket.coritan.com;
- If your policy has no
frame-src, the browser falls back tochild-srcand then todefault-src, so name the address in whichever one your policy sets. - The script sets the frame's size from JavaScript, so it needs no
'unsafe-inline'instyle-src. Thestyle="min-height: 65px"attribute on your container is your own inline style, and a policy that forbids inline styles ignores it. Put themin-heightin a stylesheet instead (Reserve the widget's height). - The frame makes its own requests to Wicket, under its own policy. Your
connect-srcdoes not need Wicket's address.
Result
Section titled ResultA visitor who passes sees Success in the widget, and your form sends a wicket-response field. Your server's verify call answers "success": true, with the hostname of your page.
Troubleshooting
Section titled TroubleshootingTroubleshoot Wicket lists what each message in the widget means, and what to do when the widget does not appear, when your server refuses a token and when a visitor cannot pass.
Related
Section titled RelatedNext steps
Section titled Next steps- Verify a token on your server so your server checks every form.
- Test keys to try the page and your server without a real widget.
- Move from Cloudflare Turnstile to Wicket if the page uses Turnstile now.