Skip to content
Coritan Docs

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.

View as Markdown

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).

  • You need a widget, with its site key (it starts with wk_) and its secret key (it starts with wks_). 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.com covers www.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 plain http:// 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, localhost included.
  1. Add 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>
    
  2. Add a div with the class wicket-widget inside the form, where the check should appear. Its data-sitekey is 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>
    
  3. 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.

A 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:

In your stylesheet
.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:

CSS
.signup-check {
  min-height: 140px;
}

Put 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.

When 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 a callback to 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 server

Never 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.

Use explicit rendering when the page builds its forms in JavaScript, or when you want to choose when the widget appears.

  1. Add ?render=explicit to the script address. Add &onload=onWicketLoad to be called when the script is ready:

    HTML
    <script src="https://wicket.coritan.com/v1/api.js?render=explicit&onload=onWicketLoad" async defer></script>
    
  2. Define the function the script calls, and render a widget in an element or a selector:

    JavaScript
    function onWicketLoad() {
      const id = wicket.render("#signup-check", {
        sitekey: "wk_...",
        callback: (token) => console.log("Passed", token),
      });
    }
    

    wicket.render returns the widget's id. The options you pass override the container's data- attributes.

Put several widgets on one page

Section titled Put several widgets on one page

Every 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.render returned, the container element or a selector to wicket.getResponse, wicket.reset and wicket.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 app

A 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:

JavaScript
// 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 callback and expired-callback, or read it with wicket.getResponse(id) when you submit.
  • Give the container its min-height in your stylesheet (Reserve the widget's height), so the page does not move when a route draws the widget.

An 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:

HTML
<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 Policy

If 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:

Text
script-src https://wicket.coritan.com;
frame-src https://wicket.coritan.com;
  • If your policy has no frame-src, the browser falls back to child-src and then to default-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' in style-src. The style="min-height: 65px" attribute on your container is your own inline style, and a policy that forbids inline styles ignores it. Put the min-height in a stylesheet instead (Reserve the widget's height).
  • The frame makes its own requests to Wicket, under its own policy. Your connect-src does not need Wicket's address.

A 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.

Troubleshoot 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.