Skip to main content


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. Please see the section below containing the possible error codes.
data-orientationportrait | landscapeOptional. Used to dictate the rotation of the hCaptcha challenge presented based on the device's orientation.

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


All of these attributes can also be used as parameters when explicitly rendering with hcaptcha.render() as described below. The parameter name is the Attribute in the table above, but without the data prefix. For example, data-tabindex is tabindex when passed into .render().

<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 code (see section below).
  • It will not inform you about expired tokens, as the promise will have already resolved with the token in this scenario.
    • To handle this case you will still need to specify the expired-callback callback.
hcaptcha.execute(widgetID, { async: true })
.then(({ response, key }) => {
console.log(response, key);
.catch(err => {

Error Codes

The following error codes are passed as argument to the error-callback function or as rejection data to the asynchronous execute.

Please note that asynchronous .execute() calls can reject the promise with extra error codes (e.g. challenge-closed) which are not passed to the error-callback as there are other callbacks (e.g. close-callback) defined for these scenarios.

In the table below, each error code is listed, along with details to interpret it and any action suggested.

If you are using hCaptcha in a fully programmatic pattern ("invisible" mode, i.e. no checkbox, with .execute() called by your functions and errors rendered in your code rather than relying on ours) then please ensure your code follows the expected behavior by described by the Action when interpreting an error.

Error CodeDescriptionAction
rate-limitedUser has sent too many requests-
network-errorThere are network connection issues (e.g. offline)hCaptcha will automatically retry several times before closing.
invalid-dataInvalid data is not accepted by endpoints-
challenge-errorChallenge encountered error on setupUser may need to select the checkbox or if invisible programmatically call execute to initiate the challenge again.
challenge-closed*User closed the challenge-
challenge-expired*Time limit to answer challenge has expired-
missing-captcha*No captcha was foundVerify hCaptcha was properly setup and a captcha was rendered.
invalid-captcha-id*Captcha does not exist for ID providedCheck to make sure the captcha rendered matches the ID stored. Each hCaptcha client rendered contains a new ID.
internal-errorhCaptcha client encountered an internal errorUser may need to select the checkbox or if invisible programmatically call execute to initiate the challenge again.
script-errorhCaptcha JS SDK could not be loadedUser may be behind a firewall that blocks api.js. Note: only present when using hcaptcha-loader.
  • * are thrown only in case of async execute

Explicitly Render hCaptcha

In the default implementation, hCaptcha widgets will be automatically rendered and inserted into your webpage. However, 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.


api.js query parameters like recaptchacompat=off are parsed on Dom.ready. Do not call hcaptcha.render() right away if you are using render=explicit to avoid racing SDK setup. Instead, call render via the function you define in api.js?onload=myFunc to ensure the SDK is fully initialized.

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


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>