Integrate captcha.eval8.ai into your website
captcha.eval8.ai — the human-verification service of the eval8 platform — protects any action — starting a test, submitting a form, creating an account — by redirecting the user through a hosted verification page. After the user passes three human-checks, they return to your site with a one-time token that your backend verifies server-to-server. One redirect out, one redirect back, one HTTP call. That's the entire integration.
Overview
Redirect
Send the user to /challenge with your public site key and a return URL.
Verify human
The user completes 3 challenges while behavioral signals are scored.
Return + token
The user comes back to your URL carrying a single-use token.
Confirm
Your backend posts secret + token to /api/siteverify → definitive yes/no.
API keys
You receive a key pair from the captcha.eval8.ai admin. The two keys have opposite rules:
| Key | Format | Visibility | Purpose |
|---|---|---|---|
| Site key | eval8-… |
Public | Identifies your website in the redirect URL. Safe to expose anywhere. |
| Secret key | eval8-secret-… |
Private | Used by your server to verify tokens. Never put it in frontend code, mobile apps, repos, or URLs. |
Every key has a whitelist of redirect domains registered at creation. The service refuses to send users to any other domain — so tell the admin every domain your site will redirect back to (subdomains of a whitelisted domain are allowed automatically).
Step 1 — Redirect the user
When the user reaches the action you want to protect, redirect their browser to:
https://captcha.eval8.ai/challenge
?site_key=eval8-your_site_key
&redirect_uri=https://yoursite.com/path-to-resume
&state=anything_you_need_to_resume
| Parameter | Required | Description |
|---|---|---|
site_key | yes | Your public site key. |
redirect_uri | yes | Absolute http/https URL on a whitelisted domain. The user is sent back here after passing. |
state | no | Opaque string (max 512 chars) returned to you unchanged. Use it to remember what the user was doing (a test ID, a session nonce). Never use it to decide trust. |
Example (Express)
// when the user clicks "Start Test" app.get('/start-test', (req, res) => { const state = saveWhereUserWas(req); // e.g. random id → {testId, userId} const url = new URL('https://captcha.eval8.ai/challenge'); url.searchParams.set('site_key', process.env.EVAL8_SITE_KEY); url.searchParams.set('redirect_uri', 'https://yoursite.com/resume-test'); url.searchParams.set('state', state); res.redirect(url.toString()); });
Step 2 — What the user sees
The verification page runs three sequential challenges, each validated server-side:
| Challenge | What happens |
|---|---|
| 🖱️ Checkbox | Mouse-only "I am not a robot" checkbox. Keyboard activation is physically impossible; cursor trajectory before the click is analyzed for human motion. |
| 🔤 Text CAPTCHA | Distorted characters generated and checked entirely server-side, with keystroke-dynamics analysis while typing. Three wrong attempts regenerate the image. |
| ⏳ Press & hold | The user holds a button until a bar fills (5–7 seconds, randomized per session, enforced on the server clock). Release-reaction timing and cursor micro-movement expose scripts. |
Behavioral signals accumulate into a suspicion score; sessions scoring as bots are refused a token and asked to retry. A typical human completes the page in 15–25 seconds.
Step 3 — Receive the user back
On success, the browser is redirected to your redirect_uri:
https://yoursite.com/resume-test?captcha_token=eval8-token-xxxx&state=your_state
The captcha_token is:
- Single-use — verifying it a second time fails.
- Short-lived — expires 5 minutes after issue.
- Bound to your site key — a token issued for another site will not verify with your secret.
Step 4 — Verify the token (server-to-server)
From your backend — never from browser JavaScript — call:
POST https://captcha.eval8.ai/api/siteverify Content-Type: application/json { "secret": "eval8-secret-your_secret_key", "token": "eval8-token-from-the-url" }
Form-encoded bodies are also accepted; secret_key, captcha_token and
response work as field aliases.
Success response
{ "success": true, "challenge_ts": "2026-07-24T10:15:30.000Z", "hostname": "yoursite.com" }
Failure response
{ "success": false, "error-codes": ["invalid-token"] }
Example (Express)
app.get('/resume-test', async (req, res) => { const { captcha_token, state } = req.query; const r = await fetch('https://captcha.eval8.ai/api/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: process.env.EVAL8_SECRET_KEY, token: captcha_token }), }); const result = await r.json(); if (!result.success) return res.redirect('/verification-failed'); const resumed = loadWhereUserWas(state); // your own state lookup res.redirect('/test/' + resumed.testId); // ✅ user is human — continue });
Example (curl — any language can do this)
curl -X POST https://captcha.eval8.ai/api/siteverify \ -H "Content-Type: application/json" \ -d '{"secret":"eval8-secret-xxx","token":"eval8-token-xxx"}'
Error codes
| Code | Meaning |
|---|---|
missing-input | Secret or token not sent. |
invalid-input-secret | Secret key unknown or revoked. |
invalid-token | Token doesn't exist, belongs to another key, or was already used. |
token-expired | Token older than 5 minutes. |
Rules your integration must follow
- Verify on the backend. Calling
/api/siteverifyfrom browser JavaScript would expose your secret key to everyone. - Verify before granting access. The presence of
captcha_tokenin a URL means nothing untilsiteverifyreturnssuccess: true. - Treat
stateas a bookmark, not a credential. Tie it to your own session or database so one user's token can't resume another user's flow. - Handle failure. On
success: false, send the user through the challenge again.
What the service stores
| Data | Lifetime |
|---|---|
| API keys — name, site key, hash of secret, domain whitelist, usage counters | Until deleted |
| Challenge sessions — step progress, suspicion score, behavior flags | 15 min (deleted immediately on success) |
| Verification tokens — value, key reference, used flag | 10 min, single-use |
Raw mouse and keystroke telemetry is scored in memory and never persisted — only the resulting score and flag names exist for the life of the short session.
Bot detection — what it catches
Detected and refused: pure HTTP bots (can't solve the captcha, can't skip the
server-enforced hold time), naive page scripts (element.click() events are untrusted),
Selenium / Puppeteer with default settings, recorded macros with linear or constant-velocity
mouse paths, and scripted holds that release with robotic timing.
Not reliably detected (true of every CAPTCHA, including commercial ones): sophisticated bots using humanized mouse-simulation libraries, and human solving farms. Layer your own rate limiting on top for sensitive actions.