hCaptcha vs reCAPTCHA: differences, tokens, and solving.
hCaptcha and reCAPTCHA both hand the browser a short-lived, single-use token that your backend verifies. They load from different scripts, write to different fields, verify at different endpoints, and their scores point in opposite directions. This guide puts them side by side, shows how to tell which one a page runs, and covers what changes when a site switches.
What each one is
hCaptcha is built by Intuition Machines. The classic flavour shows an
image-grid challenge; it also ships an invisible mode and an
enterprise mode that binds each challenge to a fresh rqdata
blob and the visitor’s session. hCaptcha describes itself as API-compatible with
reCAPTCHA v2, which is why a migration is mostly a find-and-replace.
reCAPTCHA is Google’s captcha. v2 is the familiar
“I’m not a robot” checkbox (with an optional invisible variant) that may pop an image
challenge. v3 works differently: it runs silently and never
interrupts the user, returning a risk score your server acts on.
reCAPTCHA now sits inside Google Cloud Fraud Defense. Keys still managed
in the reCAPTCHA Admin console are what Google calls reCAPTCHA Classic; keys in a Google
Cloud project use the enterprise.js script and an assessment API.
hCaptcha vs reCAPTCHA at a glance
| hCaptcha | reCAPTCHA | |
|---|---|---|
| Vendor | Intuition Machines (IMK) | Google, now part of Google Cloud Fraud Defense |
| Widget script | js.hcaptcha.com/1/api.js | www.google.com/recaptcha/api.js (v2, v3 with ?render=), enterprise.js on Google Cloud keys |
| Container class | h-captcha | g-recaptcha (v3 may put it on a submit button or use no markup at all) |
| JavaScript global | hcaptcha, plus a grecaptcha compatibility hook unless recaptchacompat=off | grecaptcha, grecaptcha.enterprise on Google Cloud keys |
| Token field | h-captcha-response | g-recaptcha-response |
| Token validity | ~120s, single-use | ~120s, single-use |
| Verify endpoint | api.hcaptcha.com/siteverify | google.com/recaptcha/api/siteverify, or an assessment on recaptchaenterprise.googleapis.com |
| Verify parameters | secret, response, remoteip (recommended), sitekey (optional) | secret, response, remoteip (optional) |
| Expired or reused token | expired-input-response, already-seen-response | timeout-or-duplicate |
| Common modes | Checkbox, invisible, enterprise (rqdata) | v2 checkbox, v2 invisible, v3 score, enterprise |
| Friction model | Image-grid challenge (or invisible pass) | v2 may challenge; v3 never interrupts |
| Score | Enterprise only: score + score_reason, a risk score (higher is riskier) | v3 and Enterprise: 0.0 to 1.0, where 1.0 is very likely a good interaction |
| Sitekey binding | Checkable via sitekey on siteverify | Tied to the key pair you verify with |
Token mechanics: the part that trips people up
Both services follow the same shape: the widget runs on the page, the user (or an
invisible check) passes, and the captcha injects a token into a hidden field that rides
along with the form post. Your backend then calls the vendor’s siteverify
endpoint to confirm it. The fields are not interchangeable:
<div class="h-captcha" data-sitekey="f5ab1c2d-..."></div>
<!-- after a solve, hCaptcha injects: -->
<textarea name="h-captcha-response">P1_eyJ0eXAi...UV8w</textarea> <div class="g-recaptcha" data-sitekey="6Lc...ABC"></div>
<!-- after a solve, reCAPTCHA injects: -->
<textarea name="g-recaptcha-response">03AGdBq2...9fH</textarea>
A few properties matter if you’re automating this. Validity is short:
both tokens default to roughly 120 seconds. hCaptcha returns
expired-input-response past that window, and reCAPTCHA tokens likewise expire two
minutes after issue. Both are also single-use. Resubmit one and you get
already-seen-response (hCaptcha) or timeout-or-duplicate (reCAPTCHA,
which uses one code for both cases). And a token is effectively bound to the sitekey
it was minted for: hCaptcha lets you enforce that by passing the sitekey
to siteverify, and reCAPTCHA ties the token to the key pair you verify with. A token issued on
one sitekey does not verify on another.
Siteverify side by side
The two classic verify calls look almost the same. Both take a POST with
secret and response. hCaptcha wants the parameters as a form body
and refuses JSON, recommends remoteip (on Enterprise it also enables risk
scores), and accepts an optional sitekey so a token issued on another sitekey
cannot be redeemed on yours. reCAPTCHA takes remoteip as optional and has no
sitekey parameter.
curl https://api.hcaptcha.com/siteverify \
-d secret="$HCAPTCHA_SECRET" \
-d response="$TOKEN" \
-d remoteip="$USER_IP" \
-d sitekey="f5ab1c2d-7e8f-4a9b-b1c2-d3e4f5a6b7c8" curl https://www.google.com/recaptcha/api/siteverify \
-d secret="$RECAPTCHA_SECRET" \
-d response="$TOKEN" \
-d remoteip="$USER_IP"
Both answer with success, challenge_ts, hostname and an
optional error-codes array. hCaptcha Enterprise adds score and
score_reason. reCAPTCHA v3 adds score and action, and
on Android returns apk_package_name in place of hostname. hCaptcha
warns that hostname comes from the user’s browser, so treat it as a statistic,
never as authentication.
Keys in a Google Cloud project can still use siteverify, but the newer path is an
assessment: a JSON POST carrying the token, the key, the action you
expected, and optionally the user agent and IP. The answer’s
tokenProperties.valid and tokenProperties.action say whether the
token is good for that action, and riskAnalysis.score carries the score with
reason codes such as AUTOMATION. Google sets the same limits: one use per token,
and an assessment within two minutes.
curl "https://recaptchaenterprise.googleapis.com/v1/projects/PROJECT_ID/assessments?key=API_KEY" \
-H "Content-Type: application/json" \
-d '{
"event": {
"token": "TOKEN",
"siteKey": "KEY_ID",
"expectedAction": "LOGIN",
"userAgent": "USER_AGENT",
"userIpAddress": "USER_IP"
}
}' The full hCaptcha request, response and error list is in hCaptcha siteverify and hCaptcha error codes.
Checkbox vs score vs invisible
The biggest conceptual gap is between a challenge model and a score model.
- reCAPTCHA v2 checkbox and hCaptcha (regular) are challenge-first:
they may show an image grid and produce a pass/fail token. Your backend just checks
success: true. - Invisible modes (hCaptcha invisible, reCAPTCHA v2 invisible) still issue a
pass/fail token but try to clear most visitors without a visible challenge, only escalating
to a grid when risk looks high. Both are switched on the same way: put the widget class on a button, or set
data-size="invisible"on the container and callexecute(). - reCAPTCHA v3 drops the challenge entirely. It returns a 0.0 to 1.0 score
(1.0 very likely a good interaction, 0.0 very likely a bot) plus an
actionname, and hands the allow/block decision to you. Google suggests 0.5 as a starting threshold. Action names may use only letters, digits, slashes and underscores, and must not be user-specific.
The scores run in opposite directions
This is the migration bug that ships most quietly. A reCAPTCHA score is a likelihood of a good interaction, so you block low scores. An hCaptcha Enterprise score is a risk score, so you block high ones. hCaptcha’s own migration guide tells you to invert every score check when you switch:
// reCAPTCHA v3: higher means more likely human
if (verify.score < 0.5) block();
// hCaptcha Enterprise: higher means riskier, so the check flips
if (verify.score >= threshold) block(); Pick the hCaptcha threshold from your own traffic; the reCAPTCHA number does not carry over.
How to tell which captcha a page uses
Open the page where the captcha actually appears (many sites load it only on the form step) and look for these markers:
- Script source.
js.hcaptcha.com/1/api.jsis hCaptcha.google.com/recaptcha/api.jsis reCAPTCHA v2 or v3 (v3 adds?render=with the sitekey), andgoogle.com/recaptcha/enterprise.jsis a Google Cloud key. hCaptcha Enterprise sites can serve hCaptcha from their own subdomain, so a missinghcaptcha.comscript does not rule hCaptcha out. - Container and field. An
h-captchaclass or anh-captcha-responsefield is hCaptcha; ag-recaptchaclass is reCAPTCHA. reCAPTCHA v3 may put that class on a submit button or use no markup at all, so check the script as well. - JavaScript globals. A global
hcaptchaobject means hCaptcha. A globalgrecaptchaproves nothing on its own: hCaptcha’srecaptchacompatoption, on by default, inserts agrecaptchahook so reCAPTCHA-era code keeps running.
Paste this into the DevTools console to check all three at once:
const srcs = [...document.scripts].map((s) => s.src);
({
hcaptcha:
typeof window.hcaptcha !== "undefined" ||
srcs.some((u) => u.includes("hcaptcha.com/1/api.js")) ||
!!document.querySelector('.h-captcha, [name="h-captcha-response"]'),
recaptcha:
srcs.some((u) => /\/recaptcha\/(api|enterprise)\.js/.test(u)) ||
!!document.querySelector(".g-recaptcha"),
recaptchaEnterprise: srcs.some((u) => u.includes("/recaptcha/enterprise.js")),
});
If hcaptcha comes back true, read the sitekey next; our
sitekey guide covers the visible, invisible and
programmatic cases.
Migrating between them
reCAPTCHA v2 to hCaptcha is the well-trodden direction. Create a sitekey and secret in the hCaptcha dashboard, then swap the script, the container class, the form field your server reads, and the siteverify URL. Callbacks and tag attributes stay the same.
<!-- client -->
- <script src="https://www.google.com/recaptcha/api.js" async defer></script>
+ <script src="https://js.hcaptcha.com/1/api.js" async defer></script>
- <div class="g-recaptcha" data-sitekey="6Lc...ABC"></div>
+ <div class="h-captcha" data-sitekey="10000000-ffff-ffff-ffff-000000000001"></div>
<!-- server -->
- token = form["g-recaptcha-response"]
+ token = form["h-captcha-response"]
- POST https://www.google.com/recaptcha/api/siteverify
+ POST https://api.hcaptcha.com/siteverify (with the hCaptcha secret) - Coming from v3 or Enterprise scores? Invert the score checks, as above.
- Pass the
sitekeyto siteverify. reCAPTCHA had no such parameter, so ported backends usually leave it out, and hCaptcha recommends it. - Send the form body. hCaptcha’s siteverify does not accept JSON, so a reCAPTCHA client that posted JSON needs changing.
- Test before you go live with hCaptcha’s test sitekeys, which provide no anti-bot protection and belong in test environments only.
hCaptcha to reCAPTCHA is the same swap in reverse for a v2 checkbox. Moving to
v3 or a Google Cloud key is a bigger change: there is no widget to render, the page calls
grecaptcha.execute() (or grecaptcha.enterprise.execute()) with an
action, and the backend has to check the action and the score as well as validity.
Privacy positioning
hCaptcha leans on privacy in its own docs: it says it is “not in the business of selling individually targeted ads”, and Enterprise customers get options to pre-blind user data before it reaches hCaptcha, such as removing the user’s IP. Its FAQ also notes that many parts of the world require you to disclose data processors, so name it in your privacy policy. Whichever you run, read the vendor’s privacy terms for the regions you serve.
Detection and difficulty
Because v3 is purely behavioural, there’s no grid to “solve.” The hard part is producing a
request that scores like a human across reputation, history, and execution signals.
hCaptcha enterprise leans the other way: each session carries an IP- and session-bound
rqdata payload, so a token has to match that session rather than come from image
recognition in isolation. Both raise the bar versus a plain checkbox, just in different places.
v3 leans on behavioural reputation, enterprise hCaptcha on session-bound challenge data.
How programmatic solving differs
For a challenge-style captcha (hCaptcha regular/invisible, reCAPTCHA v2), a solver’s
job is concrete: produce a valid token and you submit it as the matching *-response field.
For score-style reCAPTCHA v3 there is no token to “win.” Passing depends on the whole
request looking trustworthy, which is a harder, fuzzier target.
NoneCap is a hosted hCaptcha solver. You POST a sitekey and url,
optionally block for the result with ?wait=N, and read back a real P1_ token
that you submit as the page’s h-captcha-response:
curl "https://api.nonecap.com/v1/solves?wait=90" \
-H "Authorization: Bearer $NONECAP_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "hcaptcha",
"sitekey": "f5ab1c2d-7e8f-4a9b-b1c2-d3e4f5a6b7c8",
"url": "https://target.example/login"
}' {
"id": "solve_01HQF7K3JKWZX",
"object": "solve",
"type": "hcaptcha",
"status": "solved",
"token": "P1_eyJ0eXAi...UV8w",
"credits_charged": 1
}
NoneCap returns tokens that enterprise (rqdata) sitekeys accept, not just
image-recognition output. See the API reference for the
full solve object, the enterprise fields, and every language sample.
Which solver covers which
To be clear about scope: NoneCap solves hCaptcha only, covering regular, invisible, and enterprise
rqdata. It does not solve reCAPTCHA v2 or v3, Cloudflare Turnstile, or FunCaptcha today; those are on the roadmap, not shipped. If your target uses reCAPTCHA, NoneCap won’t help yet. If it’s hCaptcha, including the enterprise variant that breaks image-only solvers, that’s exactly what NoneCap is built for.
Last updated October 2026.
Frequently asked
Are hCaptcha and reCAPTCHA tokens interchangeable?
h-captcha-response token verified at api.hcaptcha.com/siteverify; reCAPTCHA returns a g-recaptcha-response token verified at Google’s endpoint. The two are issued, formatted, and validated by different vendors, so a token from one is never accepted by the other.How long is a captcha token valid?
expired-input-response after ~120s and already-seen-response on reuse; reCAPTCHA tokens also expire two minutes after issue and fail with timeout-or-duplicate when too old or already verified. Mint the token close to the moment you submit the form.What is the difference between reCAPTCHA v2 and v3?
How can I tell whether a site uses hCaptcha or reCAPTCHA?
js.hcaptcha.com/1/api.js script, an h-captcha container, an h-captcha-response field or a global hcaptcha object means hCaptcha. A google.com/recaptcha/api.js or enterprise.js script or a g-recaptcha container means reCAPTCHA. Do not go by window.grecaptcha alone: hCaptcha inserts a grecaptcha compatibility hook by default.How hard is it to switch a site from reCAPTCHA to hCaptcha?
h-captcha-response on the server. Callbacks and tag attributes stay as they are. If you consumed reCAPTCHA v3 or Enterprise scores, invert your score checks.Is reCAPTCHA now Google Cloud Fraud Defense?
Does NoneCap solve reCAPTCHA?
h-captcha-response tokens, including invisible and enterprise rqdata sitekeys. reCAPTCHA, Cloudflare Turnstile, and FunCaptcha are on the roadmap but are not available yet, so do not point a reCAPTCHA workload at it.