“How do I verify a CAPTCHA token on my server?”
How do I verify a CAPTCHA token on my server?
Short answer
Send the visitor's token and your site key from your server to your CAPTCHA provider, never from the browser. With CaptchaKit, POST to https://captchakit.com/api/verify with an Authorization: Bearer API key and a JSON body of token and siteKey. Reject the form if success is false.
Steps
- 1
Read the token in the browser
When the visitor passes, CaptchaKit writes the signed token into the widget div's data-token attribute and fires a gamecaptcha:pass event on the document. Read it on submit and send it with your form data.
- 2
Receive it on your server
In your form handler, pull out the token field along with the rest of the submission, before you create the user or send the email.
- 3
Call the verify endpoint
POST to https://captchakit.com/api/verify with the header Authorization: Bearer YOUR_API_KEY, Content-Type: application/json, and the body { "token": "...", "siteKey": "gc_..." }. Keep the API key in an environment variable.
- 4
Check success
A valid, unused token returns { "success": true, "gameId": "connect4" }. A failure returns { "success": false, "error": "Invalid or expired token" }. Reject the request on false.
- 5
Treat each token as single use
A second verify of the same token returns success: false with a Token already used message, and tokens expire after 10 minutes. Do not cache a pass.
Why it has to be your server
Anyone can edit JavaScript in their own browser, so a check that only runs in the page proves nothing. The server step is the one a script cannot skip. Keep your API key on the server, never in page code. The CaptchaKit docs say to call the endpoint from your server and never from the browser.
A Node example
In an Express handler: read gamecaptchaToken from req.body, call fetch('https://captchakit.com/api/verify') with method POST, the Bearer header and a JSON body of token and siteKey, then read { success, gameId } from the response. If success is false, return a 400 and stop before createUser runs. Python (requests.post with headers and json) and PHP (curl with CURLOPT_POSTFIELDS) follow the same shape. All three examples are in the docs.
The front end
The widget is one script tag and one div, shown below from the docs. On submit, read the token with querySelector('[data-gamecaptcha]').dataset.token and block the submit if it is empty.
<script src="https://captchakit.com/widget.js"></script>
<div data-gamecaptcha data-site-key="gc_connect4_your_key_here" data-game="connect4"></div>What happens behind the token
Before a token exists, the game must request a single-use challenge, play for at least 1.2 seconds and report interaction, within per-site-key rate limits. The pass token is a signed JWT. Its identifier is consumed on first use, which is why replays fail. See what is a game CAPTCHA for the whole flow.
This server check is one layer. For payment forms and account recovery, add your own rate limits and monitoring too, as covered in are game CAPTCHAs secure.
On WordPress
If you use the WordPress plugin, the plugin does this call for you. Use the manual flow for custom forms or other stacks.
Handling errors and edge cases
Treat anything other than success: true as a failure, including network errors from the verify call. Decide in advance whether a failed call blocks the form or lets it through, and log the decision. For most forms blocking is safer. Show a plain message that asks the visitor to try again.
Do not store tokens. A token is for one decision. If the visitor submits twice, they need to pass again. Keep your API key in an environment variable and rotate it if it leaks. If a form can be submitted by an API client with no browser, require the token there too.
Framework notes
In Next.js, load widget.js with next/script and verify in a Route Handler using an environment variable for the API key. In React, read the token from a ref on the widget div. In Vue, load the script on mount and read data-token from the element ref. In Express, Django or plain PHP, the pattern is the same: read the token field, call the endpoint, reject on false. The docs include each of these.
Questions
Which header does the verify call need?
Authorization: Bearer YOUR_API_KEY, plus Content-Type: application/json.
What does the request body contain?
A token and your siteKey.
How long is a token valid?
10 minutes, and each token works once.
Can I verify in the browser?
No. Call the endpoint from your server so your API key stays private.
What does a failed check return?
{ "success": false, "error": "Invalid or expired token" } for an invalid token, and success: false for one already used.
Where are the code samples?
In the docs, in Node, Python and PHP, with React, Next.js and Vue front ends.
Do I send the API key from the browser?
Never. The API key belongs on your server, in an environment variable.
Sources
- CaptchaKit documentation (checked 2026-10-17)
Related
Protect your forms with a game
Every arcade CAPTCHA we make. Sign up, grab your embed code, protect your forms today.
Get started →Pay what you want. Start free.