@vcaptcha/node
v1.0.3
Published
Official Node.js client library for vCaptcha — passive bot detection for web forms
Maintainers
Readme
@vcaptcha/node
Official Node.js client library for vCaptcha — passive bot detection for web forms.
What is vCaptcha?
vCaptcha protects your forms from bots using passive behavioral analysis. Most real visitors pass with zero interaction — no checkboxes, no puzzles. Bots that fail passive scoring are shown a lightweight challenge.
Installation
npm install @vcaptcha/nodeZero dependencies. Works with Node.js 18+ using the built-in fetch.
Quick Start
const { vCaptcha } = require('@vcaptcha/node');
const result = await vCaptcha.verify({
secret: process.env.VCAPTCHA_SECRET,
response: req.body['vcaptcha-response'],
remoteIp: req.ip,
});
if (!result.success) {
return res.status(400).json({ error: result.errorMessage() });
}Usage
Express
const express = require('express');
const { vCaptcha } = require('@vcaptcha/node');
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.post('/contact', async (req, res) => {
const result = await vCaptcha.verify({
secret: process.env.VCAPTCHA_SECRET,
response: req.body['vcaptcha-response'],
remoteIp: req.ip,
});
if (!result.success) {
return res.status(400).json({ error: result.errorMessage() });
}
// Optional: reject low-trust scores
if (result.score < 35) {
return res.status(400).json({ error: 'Suspicious activity detected.' });
}
// Process form...
res.json({ success: true });
});Next.js App Router
import { vCaptcha } from '@vcaptcha/node';
export async function POST(request) {
const body = await request.json();
const result = await vCaptcha.verify({
secret: process.env.VCAPTCHA_SECRET,
response: body['vcaptcha-response'],
});
if (!result.success) {
return Response.json({ error: result.errorMessage() }, { status: 400 });
}
// Process...
return Response.json({ success: true });
}Simple boolean check
const passed = await vCaptcha.check(
process.env.VCAPTCHA_SECRET,
req.body['vcaptcha-response'],
50 // optional minimum score (0-100)
);
if (!passed) {
return res.status(400).json({ error: 'Captcha required.' });
}Frontend Setup
Invisible mode (recommended)
<form method="POST" action="/contact">
<!-- your fields -->
<div class="vcaptcha" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Send</button>
</form>
<script src="https://www.vcaptcha.com/1/api.js?k=YOUR_SITE_KEY" async defer></script>Checkbox mode
<form method="POST" action="/contact">
<!-- your fields -->
<div class="vcaptcha" data-sitekey="YOUR_SITE_KEY" data-size="checkbox"></div>
<button type="submit">Send</button>
</form>
<script src="https://www.vcaptcha.com/1/api.js?k=YOUR_SITE_KEY" async defer></script>The widget automatically injects a hidden vcaptcha-response field into the form when the visitor passes verification.
API
vCaptcha.verify(options) → Promise<vCaptchaResult>
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| secret | string | ✅ | Your vCaptcha secret key |
| response | string | ✅ | Token from the visitor's browser (vcaptcha-response field) |
| remoteIp | string | — | Visitor's IP address (recommended) |
| verifyUrl | string | — | Override the verification endpoint |
| timeout | number | — | Request timeout in ms (default: 10000) |
vCaptchaResult
| Property | Type | Description |
|----------|------|-------------|
| success | boolean | Whether verification passed |
| score | number | Trust score 0–100 (higher = more human) |
| method | string | 'passive' or 'interactive' |
| errorCodes | string[] | Error codes if success is false |
| hostname | string | Hostname from the request |
| challengeTs | string | ISO timestamp of the challenge |
vCaptchaResult.errorMessage() → string
Returns a human-readable message for the first error code.
vCaptchaResult.meetsScore(minScore) → boolean
Returns true if success is true and score >= minScore.
vCaptcha.check(secret, response, minScore?) → Promise<boolean>
Convenience wrapper — returns a simple boolean.
Error Codes
| Code | Description |
|------|-------------|
| missing-input-secret | Secret key not provided |
| invalid-input-secret | Secret key is invalid |
| missing-input-response | Token not provided |
| invalid-input-response | Token is invalid or expired |
| score-too-low | Score below minimum threshold |
| rate-limited | Too many requests |
| timeout-or-duplicate | Token already used or expired |
| connection-failed | Could not reach vCaptcha servers |
Configuration
// Override the verify endpoint (for custom deployments)
vCaptcha.verifyUrl = 'https://www.vcaptcha.com/siteverify';
// Custom timeout per request
const result = await vCaptcha.verify({
secret: process.env.VCAPTCHA_SECRET,
response: token,
timeout: 5000,
});Older Node.js
For Node.js < 18 without built-in fetch, use axios:
const axios = require('axios');
const qs = require('qs');
const res = await axios.post(
'https://www.vcaptcha.com/siteverify',
qs.stringify({ secret, response, remoteip }),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, timeout: 10000 }
);
const result = res.data;Getting Your Keys
Sign up at vcaptcha.com and create a site key from your dashboard. You'll get:
- Site key — public, goes in your HTML
- Secret key — private, used server-side only. Never expose it in client-side code.
Requirements
- Node.js 18+ (uses built-in
fetch) - A vCaptcha account — free tier available
Links
License
MIT — © vCaptcha LLC
The vCaptcha backend service is proprietary. This client library is open source.
