There are two ways to configure hCaptcha. The first is to pass query parameters when loading the hCaptcha javascript resource. Using query params, you can specify a custom callback function, defer rendering, or force a specific localization.

onload<function name>Optional. The name of your custom callback function to be called once the hCaptcha API has loaded. Must be defined before the API loads.
renderexplicit | onloadOptional. Whether or not to render the widget automatically. Defaults to onload, which will automatically render widgets in hcaptcha div containers.
hl<language code>Optional. Forces a specific localization. By default, hCaptcha auto-detects the user's locale. See language codes. Can also be used via render method.
recaptchacompaton | offOptional. Whether or not to insert window.grecaptcha compatibility hook. Defaults to on.

Query params are set as key=value pairs following a ? after the script name. For example, to explicitly render captchas in French, your script tag should look like this:

<script src="" async defer></script>

Multiple query params are separated by &.

A note on the reCAPTCHA .ready() method

Because hCaptcha does not fire the onload until setup is complete, it is not necessary to wait via a .ready() method. Simply trigger any code or state change you need via the onload, and when it fires hCaptcha will already be ready for further programmatic interaction.

hCaptcha Container Configuration#

The second way to configure hCaptcha is to set custom attributes on the hCaptcha container <div>. You're already required to do this with data-sitekey, but there are a handful of other optional attributes that enable more customization.

data-sitekey<your site key>Required. Your public API site key.
data-themelight | darkOptional. Set the color theme of the widget. Defaults to light.
data-sizenormal | compactOptional. Set the size of the widget. Defaults to normal.
data-tabindex<integer>Optional. Set the tabindex of the widget and popup. When appropriate, can make navigation more intuitive on your site. Defaults to 0.
data-callback<function name>Optional. Called when the user submits a successful response. The h-captcha-response token is passed to your callback.
data-expired-callback<function name>Optional. Called when the passcode response expires and the user must re-verify.
data-chalexpired-callback<function name>Optional. Called when the user display of a challenge times out with no answer.
data-open-callback<function name>Optional. Called when the user display of a challenge starts.
data-close-callback<function name>Optional. Called when the user dismisses a challenge.
data-error-callback<function name>Optional. Called when hCaptcha encounters an error and cannot continue. If you specify an error callback, you must inform the user that they should retry.

Besides the required data-sitekey, you can add as many or as few configuration attributes as you want.


All of the above attributes can also be used as param arguments when explicitly rendering with hcatpha.render() (described in the next section). In that case, the param name is as shown above, but without the data prefix. For example, the param argument for data-tabindex is just tabindex.

<script type="text/javascript">
hcaptcha.render('captcha-1', {
sitekey: 'your_site_key',
theme: 'dark',
'error-callback': 'onError',

JavaScript API#

The hCaptcha API exposes the hcaptcha object that has methods you may find useful in customizing hCaptcha behavior.

hcaptcha.render(container, params)#

Renders the hCaptcha widget inside the container DOM element. Returns a unique widgetID for the widget.

  • container The string ID of the container or the container DOM element.
  • params An object containing config parameters as key=value pairs. Ex:
    "theme": "dark",
    "size": "compact",
    "sitekey": "your_site_key"


Resets the hCaptcha widget with widgetID.

  • widgetID Optional unique ID for a widget. Defaults to first widget created.


Gets the response for the hCaptcha widget with widgetID.

  • widgetID Optional unique ID for a widget. Defaults to first widget created.


Gets the response ID for the hCaptcha widget with widgetID.

  • widgetID Optional unique ID for a widget. Defaults to first widget created.


Triggers the hCaptcha workflow programmatically. Generally used in invisible mode where the target container is a div rather than a button.

  • widgetID Optional unique ID for a widget. Defaults to first widget created.

Asynchronous mode#

Optionally, you can pass { async: true } to hcaptcha.execute() in order to get a promise back.

  • Upon successful completion of the challenge, it will resolve with an object containing the token and the response key.
  • in case of an error, it will reject with an appropriate error message.
hcaptcha.execute(widgetID, { async: true })
.then(({ token, key }) => {
console.log(token, key);
.catch(err => {

Explicitly Render hCaptcha#

In the default implementation, hCaptcha widgets will be automatically rendered and inserted into your webpage. Howevever, you can also defer rendering by specifying a custom onload callback function in which you render the widget yourself.

To specify a custom onload callback function, you must pass the function name as an onload query parameter in the hCaptcha javascript tag. In addition, you must set the render query parameter to explicit. Your hCaptcha script tag should look like this (replace yourFunction with the name of your function):


Your custom callback function must be defined before the hCaptcha script loads. You can then call hcaptcha.render with the container ID and your site key to explicitly render the widget.

<script type="text/javascript">
var yourFunction = function () {
console.log('hCaptcha is ready.');
var widgetID = hcaptcha.render('captcha-1', { sitekey: 'your_site_key' });

Promisifying Response Handling#

Sometimes it is useful to explicitly await a token. This can be done by using the callbacks provided. A fully worked example is below:

function hCaptchaAsync(element="hcaptcha", config={}) {
if (!config.sitekey)
throw new Error("hCaptha requires sitekey");
let resolve, reject;
const id = hcaptcha.render(element, {
sitekey: config.sitekey,
theme: config.theme || "light",
"callback": onSuccess,
"error-callback": onError,
"close-callback": onClose
function onSuccess(response) {
function onError(message) {
function onClose() {
console.log("user closed challenge.");
reject(new Error("hCaptcha user closed challenge"));
function execute() {
const executePromise = new Promise((res, rej) => resolve = res, reject = rej);
return executePromise;
return {
const captcha = new hCaptchaAsync();
const token = await captcha.execute();


You can apply a dark theme to the hCaptcha widget by setting the data-theme attribute of the hCaptcha container to dark.

hCaptcha dark theme example.

<div class="h-captcha" data-sitekey="your_site_key" data-theme="dark"></div>

There's also a compact option to give the widget a smaller footprint. Set the data-size attribute of the hCaptcha container to compact.

hCaptcha compact theme example.

<div class="h-captcha" data-sitekey="your_site_key" data-size="compact"></div>