Skip to content

CAPTCHA Widget Overview

Here we explain how the TrustCaptcha CAPTCHA widget can be integrated and customized into any website frontend.

You can use TrustCaptcha with all common technologies and frameworks based on JavaScript. Server-side rendering (SSR), static site generation (SSG), and single-page applications (SPA) are all supported. There is a pure JavaScript library; separate npm packages exist for Angular, React, and Vue.js. A community-maintained Svelte integration is also available.


This is how (or similarly) the implementation of the TrustCaptcha component on your website can look. Please refer to the respective tutorial that matches your programming language or framework.

Sample code
<form>
<!-- your input fields -->
<trustcaptcha-component
sitekey="<your_site_key>"
></trustcaptcha-component>
<!-- further input fields / submit button -->
</form>

The TrustCaptcha component contains a range of properties, methods, and events. Below you’ll find a listing of all of them.


Here is an overview of all available properties, methods, and events of the CAPTCHA widget.

NameTypeDefaultDescription
sitekeyUUID stringSitekey of the CAPTCHA. You find it on the administration page of your CAPTCHA. Required.
api-urlURLhttps://api.trustcomponent.comAPI endpoint the widget talks to. Override only when you’ve been told to.
languagestringautoDisplay language. auto detects from <html lang>, falls back to English. Supported: ar, be, bg, bs, ca, cs, da, de, el, en, es, et, fi, fr, hi, hr, hu, it, ko, lb, lt, lv, mk, nl, no, pl, pt, ro, ru, sk, sl, sq, sr, sv, tr, uk, zh.
themelight | dark | medialightDisplay theme. media follows the user’s system prefers-color-scheme.
full-widthbooleanfalseWhen true, the widget stretches to the full available width of its container instead of using a fixed maximum width.
autostart-disabledbooleanfalseWhen true, the verification will not start automatically on user interaction with the form. See the autostart section below.
token-field-namestringtc-verification-tokenName of the hidden <input> field added to the form when the verification succeeds.
bypass-tokenstring | null''Bypass token from the dashboard for automated tests — makes the CAPTCHA always pass.
minimal-data-modebooleanfalseWhen true, only the minimal set of data needed to run the verification is collected. Must match the captcha mode configured in the dashboard.
failover-enabledbooleanfalseWhen true, a clearly marked failover token is issued client-side if the captcha API is unreachable. See the failover section below.
translationsstring (JSON)''Override existing translations or add new languages. See custom translations.
designstring (JSON)''Custom design overrides. See custom design. License key required
privacy-urlURL''Link to your own privacy policy displayed next to the widget. License key required
invisiblebooleanfalseHides the visible checkbox and runs the captcha in the background. License key required
invisible-hinthidden | inline | right-border | right-bottomright-borderPosition of the small “Trustcaptcha is verifying” hint shown while the invisible CAPTCHA runs. hidden shows nothing.
white-labelbooleanfalseRemoves the Trustcaptcha branding from the widget. License key required
license-keystring | nullnullLicense key that unlocks the licensed features above. You’ll find it in your CAPTCHA settings.
frameworkstring | nullnullForces a frontend framework hint sent in the verification metadata. The widget detects Angular, React and Vue automatically; only set this if the auto-detection misclassifies your stack.
NameDescription
startVerification()Starts the verification manually. Useful when you’ve disabled autostart or trigger from outside the form.
reset()Resets the widget back to its initial state and clears the verification token.
NameDetailDescription
captchaStartedvoidFires as soon as the verification process actually starts.
captchaSolvedstring (verification token)Fires when the CAPTCHA was solved successfully. The detail is the verification token to send to your backend.
captchaFailed{ errorCode, message }Fires when the CAPTCHA fails. errorCode is one of the error codes, message is a human-readable text.
captchaExpiredvoidFires shortly before the verification token expires and the widget auto-resets. Use this to reset dependent UI state.
captchaResetvoidFires whenever the widget returns to its initial state — either programmatically via reset() or after expiry.

A full example with most of the available properties and events:

<form>
<!-- your input fields -->
<trustcaptcha-component
sitekey="<your_site_key>"
full-width="true"
language="en"
theme="light"
license-key="<license-key>"
white-label="true"
translations='[{"language":"en","boxCompleted":"I am a happy human"}]'
design='{"theme":{"light":{"boxDefaultBackground":"#eab308"}}}'
privacy-url="https://www.example.com/my-privacy-policy"
invisible="true"
invisible-hint="right-bottom"
token-field-name="tc-verification-token"
bypass-token="<bypass-token>"
minimal-data-mode="false"
failover-enabled="true"
></trustcaptcha-component>
<!-- further input fields / submit button -->
</form>
<script>
const widget = document.querySelector('trustcaptcha-component');
widget.addEventListener('captchaStarted', () => { /* ... */ });
widget.addEventListener('captchaSolved', (e) => { /* e.detail = verification token */ });
widget.addEventListener('captchaFailed', (e) => { /* e.detail = { errorCode, message } */ });
widget.addEventListener('captchaExpired', () => { /* ... */ });
widget.addEventListener('captchaReset', () => { /* ... */ });
</script>

Here you will find helpful tips and tricks for integrating the TrustCaptcha component into your frontend.

By default, the verification process starts automatically as soon as a user interacts with any input field that lives inside the same <form> as the CAPTCHA widget. Both keystrokes and focus changes count as interaction. To disable this behavior entirely, set autostart-disabled="true" on the component.

Disable autostart
<form>
<!-- your input fields -->
<trustcaptcha-component
sitekey="<your_site_key>"
autostart-disabled="true"
></trustcaptcha-component>
<!-- further input fields / submit button -->
</form>

You can also opt out per input field by adding the data-autostart="false" attribute. This is honored both for focus and for typing.

Disable autostart for individual input fields
<form>
<input id="input1" name="input1">
<input id="input2" name="input2" data-autostart="false">
<trustcaptcha-component
sitekey="<your_site_key>"
></trustcaptcha-component>
<!-- further input fields / submit button -->
</form>

The translations attribute lets you override existing translations or add entirely new languages. It is a JSON array of objects; each object is identified by its mandatory language field. Visible texts as well as screen-reader-only texts can be customized individually.

The full translation object looks like this:

{
"language": "en",
"boxStart": "Start verification",
"boxInProgress": "Verification in progress",
"boxCompleted": "I am a human!",
"endPrivacyPolicy": "Privacy",
"ariaLabelStart": "CAPTCHA not started, click here to start the CAPTCHA",
"ariaLabelRunning": "CAPTCHA in process",
"ariaLabelDone": "CAPTCHA completed",
"srRunning": "CAPTCHA verification started",
"srDone": "CAPTCHA verification successfully completed",
"srFailed": "CAPTCHA verification failed",
"srExpired": "CAPTCHA verification expired, please start again",
"srTrustcaptcha": "Open the Trustcaptcha website",
"srPrivacy": "Open the privacy policy",
"srFailureReasonPrefix": "Reason",
"errorUnknown": "Unknown error.",
"errorCommunicationFailure": "Server not reachable. Please check your internet connection and try again.",
"errorPowFailure": "The bot verification failed. Please try again.",
"errorPaymentRequired": "Limit of verifications has been reached. Please contact support.",
"errorLocked": "Captcha blocked. Please contact the support."
}

When you override an existing language, fields you don’t specify keep their default. When you add a brand-new language, English is used as the fallback for any field you don’t provide.

The error* fields cover only those error situations that are actually shown to end users. Purely technical or configuration-time errors (e.g. an invalid sitekey) are not translatable — they’re aimed at developers integrating the widget, not end users.

Custom translations usage (plain HTML)

<trustcaptcha-component
sitekey="<your_site_key>"
language="en"
translations='[{ "language": "en", "boxCompleted": "I am a happy human" }]'
></trustcaptcha-component>

Custom translations usage (Angular property binding)

component.ts
public translations = JSON.stringify([
{
language: "en",
boxCompleted: "I am a happy human"
}
]);
template.html
<trustcaptcha-component
sitekey="<your_site_key>"
language="en"
[translations]="translations"
></trustcaptcha-component>

The design attribute lets you adapt the look of the widget to fit your site. Only the properties you specify are overridden — everything else keeps its default value.

The full design object looks like this:

{
"rounding": {
"box": "6px",
"checkbox": "8px",
"invisibleHint": "6px"
},
"borderWidth": {
"box": "1px",
"checkbox": "1px"
},
"theme": {
"light": {
"boxDefaultBackground": "#f9fafb",
"boxDefaultText": "#374151",
"boxDefaultBorder": "#e5e7eb",
"boxCheckboxBackground": "#ffffff",
"boxCheckboxBorder": "#e5e7eb",
"boxSuccessBackground": "#f9fafb",
"boxSuccessBorder": "#86efac",
"boxFailureBackground": "#fef2f2",
"boxFailureBorder": "#fca5a5",
"boxFailureText": "#7f1d1d",
"invisibleHintBackground": "#ffffff",
"spinnerColor": "#3b82f6",
"successIconColor": "#16a34a"
},
"dark": {
"boxDefaultBackground": "#1f2937",
"boxDefaultText": "#e5e7eb",
"boxDefaultBorder": "#374151",
"boxCheckboxBackground": "#030712",
"boxCheckboxBorder": "#374151",
"boxSuccessBackground": "#1f2937",
"boxSuccessBorder": "#15803d",
"boxFailureBackground": "#450a0a",
"boxFailureBorder": "#991b1b",
"boxFailureText": "#fecaca",
"invisibleHintBackground": "#1f2937",
"spinnerColor": "#3b82f6",
"successIconColor": "#22c55e"
}
}
}

What each field controls:

FieldEffect
rounding.boxCorner rounding of the outer widget box.
rounding.checkboxCorner rounding of the inner checkbox.
rounding.invisibleHintCorner rounding of the floating hint shown while an invisible captcha runs.
borderWidth.boxBorder width of the outer widget box.
borderWidth.checkboxBorder width of the inner checkbox.
boxDefaultBackgroundBackground while idle / running.
boxDefaultTextText color while idle / running.
boxDefaultBorderBorder color while idle / running.
boxCheckboxBackgroundBackground of the inner checkbox.
boxCheckboxBorderBorder color of the inner checkbox.
boxSuccessBackgroundBackground after a successful verification.
boxSuccessBorderBorder color after a successful verification.
boxFailureBackgroundBackground when the verification has failed.
boxFailureBorderBorder color when the verification has failed.
boxFailureTextText color when the verification has failed.
invisibleHintBackgroundBackground of the floating hint shown while an invisible captcha runs.
spinnerColorStroke color of the loading spinner.
successIconColorFill color of the success check icon.

Custom design usage (plain HTML)

<trustcaptcha-component
sitekey="<your_site_key>"
license-key="<license-key>"
design='{ "theme": { "light": { "boxDefaultBackground": "#eab308" } } }'
></trustcaptcha-component>

Custom design usage (Angular property binding)

component.ts
public design = JSON.stringify({
theme: {
light: {
boxDefaultBackground: "#eab308"
}
}
});
template.html
<trustcaptcha-component
sitekey="<your_site_key>"
license-key="<license-key>"
[design]="design"
></trustcaptcha-component>

When the CAPTCHA widget is solved, the widget receives a so-called verification token from our servers. The token is a single Base64 string and is delivered in two ways:

  1. as a hidden <input> field appended to the surrounding <form> (default name: tc-verification-token, configurable via token-field-name), and
  2. as the detail of the captchaSolved JavaScript event.

Send this token to your backend — for example as part of the form submission, or via your own API call. On the backend, validate it through one of our server SDKs or the REST API.


In rare cases the captcha API may be temporarily unreachable from a user’s network. By default the widget reports this as a COMMUNICATION_FAILURE, which means the form cannot be submitted. For workflows where availability is more important than absolute bot-protection (for example: lead forms, contact forms), you can enable an optional failover.

<trustcaptcha-component
sitekey="<your_site_key>"
failover-enabled="true"
></trustcaptcha-component>

When failover is enabled and our servers cannot be reached, the widget issues a clearly-marked failover token (the JSON payload contains clientFailover: true). The widget treats this as a successful verification and emits captchaSolved so the user can submit the form normally.

The decision what to do with such a request is made on the server side, not in the widget. Our backend SDKs surface failover tokens explicitly — typically via a dedicated exception or a flag on the verification result — so your application can:

  • accept the request (treat the failover as proof of intent and a temporary loss of API connectivity),
  • soft-challenge the user (e.g. require email confirmation), or
  • reject the request entirely.

See the server failover behavior page for details on how each backend SDK exposes the failover signal.


If the CAPTCHA widget is misconfigured or an error occurs during verification, the widget emits the captchaFailed event. The event detail contains a structured error model:

{
"errorCode": "UNKNOWN_ERROR",
"message": "Unknown error."
}

errorCode identifies the exact error class (machine-readable, stable across releases) and lets you implement programmatic error handling. message is a human-readable text — for end-user-facing errors it’s already translated according to the active widget language.

Error CodeDescription
UNKNOWN_ERRORAn unexpected error occurred. Treat this as a generic failure and retry, or contact support if it persists.
NO_FORM_FOUNDThe widget is not placed inside a <form> element. Move the <trustcaptcha-component> into the surrounding form.
COMMUNICATION_FAILUREOur servers could not be reached. Usually a temporary networking issue. See failover if availability is critical.
NO_SITE_KEY_SPECIFIEDThe required sitekey attribute is missing.
SITE_KEY_FORMAT_INVALIDThe provided sitekey is not a valid UUID. Copy it again from your CAPTCHA settings.
CAPTCHA_NOT_FOUNDNo CAPTCHA exists for the configured sitekey. Most often a typo, or the captcha was deleted.
CAPTCHA_NOT_ACCESSIBLEThe captcha is not allowed to be loaded from the page’s hostname. Check the Authorized websites setting in your CAPTCHA settings.
MINIMAL_DATA_MODE_MISMATCHminimal-data-mode on the widget does not match the captcha’s mode in the dashboard. Align both sides.
POW_FAILUREThe proof-of-work challenges were not accepted by the server. Usually a transient issue — let the user retry.
PAYMENT_REQUIREDThe captcha is locked due to a billing issue. Check your subscription and payment status.
LOCKEDThe captcha is administratively locked. Please contact support.
LICENSE_FORMAT_INVALIDThe provided license-key is not a well-formed JWT.
LICENSE_INVALIDThe license signature could not be verified or the subject is not a Trustcaptcha license.
LICENSE_SITE_KEY_MISMATCHThe license was issued for a different sitekey. Use the license belonging to this captcha.
LICENSE_FEATURE_MISSING_WHITE_LABELwhite-label was set but the license does not include the white-label feature.
LICENSE_FEATURE_MISSING_INVISIBILITYinvisible was set but the license does not include the invisibility feature.
LICENSE_FEATURE_MISSING_CUSTOMIZABILITYdesign or privacy-url was set but the license does not include the customizability feature.