hCaptcha test sitekey: the official integration-testing keys.
hCaptcha publishes official test keys so you can wire up the widget and your
siteverify call without solving anything. The publisher test sitekey is
10000000-ffff-ffff-ffff-000000000001: it always passes and always emits
the same dummy token, which verifies against the all-zeros test secret. Here is the
full set, a snippet to paste, and the one error the keys trip when you mix them
wrong.
The keys
The docs list one publisher key set and two enterprise variants. All three sitekeys
render a widget that never challenges, each emits its own fixed dummy token, and all
three tokens verify against the same test secret:
0x0000000000000000000000000000000000000000.
# Publisher / Pro account keys: widget always passes, never challenges
sitekey: 10000000-ffff-ffff-ffff-000000000001
secret: 0x0000000000000000000000000000000000000000
token: 10000000-aaaa-bbbb-cccc-000000000001
# Enterprise: simulates a safe end user
sitekey: 20000000-ffff-ffff-ffff-000000000002
token: 20000000-aaaa-bbbb-cccc-000000000002
# Enterprise: simulates a detected bot
sitekey: 30000000-ffff-ffff-ffff-000000000003
token: 30000000-aaaa-bbbb-cccc-000000000003
# All three sets verify against the same test secret (the 0x00... one above). | Key set | Test sitekey | Dummy response token |
|---|---|---|
| Publisher / Pro (always passes) | 10000000-ffff-ffff-ffff-000000000001 | 10000000-aaaa-bbbb-cccc-000000000001 |
| Enterprise: safe end user | 20000000-ffff-ffff-ffff-000000000002 | 20000000-aaaa-bbbb-cccc-000000000002 |
| Enterprise: bot detected | 30000000-ffff-ffff-ffff-000000000003 | 30000000-aaaa-bbbb-cccc-000000000003 |
The two enterprise sets exist so you can exercise both branches of your handling
logic: 20000000-… simulates a clean end user, 30000000-… a
detected bot. For enterprise testing the docs also note you should pass
remoteip to siteverify, or some response fields (the risk score among
them) stay disabled.
How the test flow behaves
With a test sitekey the widget loads normally, but the round is scripted. Per the docs, the keypair “will never challenge and always produce the same response token”. Concretely:
- The checkbox passes on click; you never see an image grid or a drag puzzle.
-
The
h-captcha-responsefield gets the fixed dummy token (for the publisher key:10000000-aaaa-bbbb-cccc-000000000001), not a realP1_token like the ones described in the hCaptcha token guide. -
That dummy token returns
success: truefrom siteverify when, and only when, you verify it with the test secret.
Because the token is a constant, the whole loop is deterministic. That is the point: you are testing that your form posts the field, your backend calls siteverify, and your success and failure branches both run. You are not testing hCaptcha itself.
Minimal working page
Save this as an HTML file and serve it from anywhere (even localhost;
test keys skip domain checks). The widget renders, the checkbox passes, and the form
posts the dummy token:
<!DOCTYPE html>
<html>
<head>
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
</head>
<body>
<form action="/submit" method="POST">
<!-- Official test sitekey: renders the widget, never challenges. -->
<div class="h-captcha"
data-sitekey="10000000-ffff-ffff-ffff-000000000001"></div>
<button type="submit">Submit</button>
</form>
</body>
</html>
On the server, verify what arrived in h-captcha-response against the
test secret:
curl "https://api.hcaptcha.com/siteverify" \
-d "secret=0x0000000000000000000000000000000000000000" \
-d "response=10000000-aaaa-bbbb-cccc-000000000001" {
"success": true,
"challenge_ts": "2026-06-12T09:41:00.000Z",
"hostname": "localhost"
} The full server-side contract (parameters, response fields, production setup) is covered in the siteverify guide.
The not-using-dummy-passcode error
The test keys only work as a matched set. Mix a test value with a real one and siteverify fails with a dedicated error code:
{
"success": false,
"error-codes": ["not-using-dummy-passcode"]
}
hCaptcha documents not-using-dummy-passcode as “You have used a testing
sitekey but have not used its matching secret.” The usual ways to hit it:
- Test sitekey on the page, real secret on the server. The widget emitted the dummy token, your real secret cannot validate it.
- Test secret on the server, real token in the request. The test secret only accepts the dummy passcodes.
-
Tokens crossed between sets, e.g. the
20000000-…token verified while the page used the10000000-…sitekey.
The fix is mechanical: pick one row from the table and use its sitekey, the shared
test secret, and its dummy token together. The related
sitekey-secret-mismatch code (“The sitekey is not registered with the
provided secret.”) is the same class of mistake with real keys; both are broken down
in hCaptcha error codes.
Test keys provide no anti-bot protection. The sitekey, secret, and dummy token are public, so anyone can pass your form while they are live. The docs tell you to keep them strictly in test environments; load the key from config per environment so production can never boot with the all-zeros secret.
What the test keys cannot tell you
Everything interesting about hCaptcha in production is absent from the test flow.
The dummy round never renders a real challenge, so you learn nothing about the
challenge types your users will see,
how often multi-round challenges occur, or how your UI behaves while the iframe is
open. The token is a fixed string, so token expiry (~120 s), single-use semantics,
and already-seen-response handling go unexercised. And there is no test
path at all for enterprise rqdata binding; the enterprise test keys
simulate risk verdicts, not the
rqdata challenge flow.
To cover that gap, point your staging environment at a real sitekey
(your production one, or a second registered key) and use real tokens. If you do not
want a human clicking challenges on every CI run, mint the token through NoneCap:
send the sitekey and page URL to POST /v1/solves and you get back a real
P1_ token that behaves exactly like production, including expiry and
single use.
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://staging.your-site.example/signup"
}'
Submit the returned token as h-captcha-response and your
real secret validates it at siteverify. Billing starts at one credit per challenge round, charged on
success only, at $0.25 to $0.50 per 1,000 credits; new accounts get 100 free
credits to test with. Request details are in the
API reference, and
finding your sitekey takes a few seconds if
you do not have it handy.
Last updated June 2026.
Frequently asked
What is the hCaptcha test sitekey?
10000000-ffff-ffff-ffff-000000000001. It is the official publisher integration-testing key: the widget renders, never shows a challenge, and always produces the dummy token 10000000-aaaa-bbbb-cccc-000000000001, which verifies as success: true against the test secret 0x0000000000000000000000000000000000000000.Why am I getting not-using-dummy-passcode from siteverify?
Is there a test sitekey that always shows a challenge?
Can I ship the test sitekey to production?
Does the dummy token verify against my real secret?
10000000-aaaa-bbbb-cccc-000000000001 only returns success: true with the all-zeros test secret. Against a real secret, siteverify rejects it. The reverse mix (test secret + real token) fails with not-using-dummy-passcode. See the siteverify guide for the full verification flow.