Node
Copy sdk/node/privcaptcha.js into your project. It uses the built-in fetch, so Node 18 or
newer and no dependencies.
Verify
const { verify } = require('./privcaptcha');
const result = await verify({
secret: process.env.PRIVCAPTCHA_SECRET,
response: req.body['privcaptcha-response'],
remoteIp: req.ip,
});
if (!result.success) {
return res.status(400).json({ errors: result.errorCodes });
}
| Option | Default | Description |
|---|---|---|
secret |
— | your site secret |
response |
— | the token from the form field |
remoteIp |
null |
the visitor's IP, sent as remoteip |
endpoint |
https://privcaptcha.com/api/v1/siteverify |
override for testing |
timeoutMs |
10000 |
aborts the request after this long |
The result is { success, challengeTs, hostname, errorCodes }.
Express middleware
const { middleware } = require('./privcaptcha');
app.post(
'/signup',
middleware({ secret: process.env.PRIVCAPTCHA_SECRET }),
handler
);
On success it sets req.privcaptcha to the result and calls next(). On failure it responds
400 with { error: 'captcha_failed', codes: [...] }, unless you pass
onFail(req, res, result).
It reads the token from whichever of these fields is present, so the compatibility shims work unchanged:
privcaptcha-response
h-captcha-response
g-recaptcha-response
This requires a body parser to have run first.
Fail-closed behaviour
A timeout, a network error or a non-200 response resolves to
{ success: false, errorCodes: ['verification-unavailable'] } rather than throwing. Our
outage must not become your breach. An empty response short-circuits to
missing-input-response with no network call.