CAPTCHA Updated Jan 27, 2026

Extended

Advanced integration options, verification flow, and API reference.

SDK (Preferred)

bun add @requestguard/js
import RequestGuard from "@requestguard/js";

RequestGuard.captcha({
  el: ".rg-captcha",
  theme: "dark",
  autoVerify: false,
  onVerify: (result) => {
    document.getElementById("contact-send").disabled = !result.token;
  }
});
<div class="rg-captcha"></div>
<button id="contact-send" disabled>Send</button>

Script Tag

<script src="https://requestguard.com/js/captcha.js"></script>
<div class="rg-captcha"></div>
<button id="contact-send" disabled>Send</button>
<script>
  RequestGuard.captcha({
    el: ".rg-captcha",
    theme: "dark",
    autoVerify: false,
    onVerify: (result) => {
      document.getElementById("contact-send").disabled = !result.token;
    }
  });
</script>

What onVerify Means

When the user completes the challenge, the widget exchanges the proof-of-work solution for a short-lived verification token from RequestGuard.

With the default autoVerify: true, the SDK verifies that token in the browser by calling https://requestguard.com/api/captcha/siteverify. onVerify fires after that background check and gives you { success, token, challenge_ts }. Use this mode when the CAPTCHA is only gating client-side UX and you do not need to verify the token again on form submit.

With autoVerify: false, onVerify fires as soon as the widget returns a token and gives you { success: true, token }. Use this mode for contact forms, signup forms, checkout flows, and any workflow where your backend must verify the submitted token before processing the action.

Tokens expire quickly and are single-use by default, which prevents replay. If browser auto-verification consumes a token, a later backend verification of the same token will fail unless you explicitly call siteverify with keepToken: true.

Contact Form Pattern

<form id="contact-form">
  <input name="email" type="email" required />
  <textarea name="message" required></textarea>
  <div class="rg-captcha"></div>
  <button id="contact-send" disabled>Send</button>
</form>

<script src="https://requestguard.com/js/captcha.js"></script>
<script>
  const send = document.getElementById("contact-send");

  RequestGuard.captcha({
    el: ".rg-captcha",
    autoVerify: false,
    onVerify: (result) => {
      send.disabled = !result.token;
    },
    onReset: () => {
      send.disabled = true;
    },
    onError: () => {
      send.disabled = true;
    }
  });
</script>

On submit, read the hidden rg-captcha-token field from the form and verify it on your server before accepting the submission.

Invisible Mode

Use invisible mode to run verification in the background without showing the widget.

RequestGuard.captcha({
  el: ".rg-captcha",
  invisible: true,
  autoVerify: false,
  onVerify: (result) => {
    if (result.token) {
      document.getElementById("contact-send").disabled = false;
    }
  }
});

Language Override

Language is auto-detected from the browser by default. To force a specific language:

RequestGuard.captcha({
  el: ".rg-captcha",
  language: "de"
});

Verify Tokens Server-Side

For protected actions, set autoVerify: false and verify the submitted rg-captcha-token on your own backend.

POST https://requestguard.com/api/captcha/siteverify
{
  "response": "<token-from-client>",
  "origin": "https://example.com"
}

Response

{
  "success": true,
  "challenge_ts": "2026-01-27T10:11:12.000Z"
}

origin is optional, but recommended. It should be the origin where the widget was embedded. RequestGuard compares it with the origin recorded when the challenge was issued.

If you need to verify in the browser and then verify again on your backend, call siteverify with keepToken: true for the browser-side verification. Most form integrations should avoid that and use autoVerify: false instead.

Options

OptionTypeDescription
elstring | HTMLElementTarget element (required)
theme”auto” | “light” | “dark”Widget theme (default: auto)
invisiblebooleanHide the widget and auto-run verification (default: false)
onVerifyfunctionCalled after background verification when autoVerify is enabled, or after token redemption when autoVerify: false
onErrorfunctionCalled when the widget reports an error
onResetfunctionCalled when the widget resets
fieldNamestringHidden input name (default: rg-captcha-token)
autoVerifybooleanVerify token automatically in the browser (default: true). Set to false when your backend will verify the submitted token.
verifyUrlstringOverride verification endpoint
apistringOverride API base used by the widget (default: /api/captcha/)
hoststringOverride RequestGuard host for self-hosting
originstringOverride origin sent to RequestGuard (default: window.location.origin)
instanceIdstringCustom instance ID for multi-captcha pages
titlestringIframe title for accessibility
widthstringIframe width (default: 100%)
heightstringIframe height (default: 90px)
borderRadiusstringIframe border radius (default: 12px)

Listening for Verification

You can listen via the instance or a DOM event:

<script>
  const instance = RequestGuard.captcha({ el: ".rg-captcha" });
  instance.on("verified", (event) => {
    console.log("verified token", event.detail.token);
  });

  document.addEventListener("rg:captcha:verified", (event) => {
    console.log("verified token", event.detail.token);
  });
</script>

API Endpoints

Challenge

POST https://requestguard.com/api/captcha/challenge

Returns challenge data and a challenge token for the widget.

Redeem

POST https://requestguard.com/api/captcha/redeem

Body:

{
  "token": "<challenge-token>",
  "solutions": [123, 456, 789]
}

Returns a short-lived verification token.

Site Verify

POST https://requestguard.com/api/captcha/siteverify

Body:

{
  "response": "<verification-token>",
  "origin": "https://example.com",
  "keepToken": false
}

Notes

  • No dashboard setup or domain registration is required.
  • The widget is delivered via iframe to keep branding and updates consistent.
  • Tokens expire automatically (typically within 20 minutes).
  • Use server-side verification for security.
  • Do not verify the same token twice unless the first verification uses keepToken: true.