Node.js SDK
Server-side captcha token verification for Node.js.
Installation
npm install @crovly/nodeZero dependencies. Uses native fetch (Node.js 18+).
Basic Usage
import { Crovly } from '@crovly/node';
const crovly = new Crovly('crvl_secret_YOUR_API_KEY');
// In your route handler
const result = await crovly.verify(token, {
expectedIp: req.ip,
});
if (!result.success) {
return res.status(403).json({ error: 'Captcha failed' });
}API
new Crovly(secretKey, options?)
| Parameter | Type | Default | Description |
|---|---|---|---|
secretKey | string | — | Your API key (required) |
options.baseUrl | string | https://api.crovly.com | API base URL |
options.timeout | number | 10000 | Request timeout in ms |
crovly.verify(token, options?)
| Parameter | Type | Required | Description |
|---|---|---|---|
token | string | Yes | Token from the widget |
options.expectedIp | string | No | IP to verify against |
Returns Promise<VerifyResponse>:
interface VerifyResponse {
success: boolean;
score?: number; // 0.0 (bot) to 1.0 (human)
ip?: string; // IP that solved the challenge
solvedAt?: number; // Unix timestamp (ms)
error?: string; // Error message if failed
}Express Example
import express from 'express';
import { Crovly } from '@crovly/node';
const app = express();
const crovly = new Crovly(process.env.CROVLY_SECRET_KEY!);
app.post('/api/contact', express.json(), async (req, res) => {
const { token, name, email, message } = req.body;
const result = await crovly.verify(token, {
expectedIp: req.ip,
});
if (!result.success) {
return res.status(403).json({ error: 'Verification failed' });
}
// Process the form...
res.json({ ok: true });
});Next.js API Route
// app/api/contact/route.ts
import { Crovly } from '@crovly/node';
import { NextRequest, NextResponse } from 'next/server';
const crovly = new Crovly(process.env.CROVLY_SECRET_KEY!);
export async function POST(req: NextRequest) {
const { token, ...data } = await req.json();
const ip = req.headers.get('x-forwarded-for')?.split(',')[0] || '';
const result = await crovly.verify(token, { expectedIp: ip });
if (!result.success) {
return NextResponse.json({ error: 'Verification failed' }, { status: 403 });
}
// Process the form...
return NextResponse.json({ ok: true });
}Error Handling
The SDK throws typed errors:
import { Crovly, AuthenticationError, TimeoutError, NetworkError } from '@crovly/node';
try {
const result = await crovly.verify(token);
} catch (err) {
if (err instanceof AuthenticationError) {
// Invalid API key
} else if (err instanceof TimeoutError) {
// Request timed out
} else if (err instanceof NetworkError) {
// Network connectivity issue
}
}| Error Class | Description |
|---|---|
AuthenticationError | Invalid or missing API key (401) |
ValidationError | Invalid request data (400) |
RateLimitError | Rate limit exceeded (429) |
TimeoutError | Request timed out |
NetworkError | Network connectivity issue |
TypeScript
Full type definitions included:
import type { CrovlyOptions, VerifyOptions, VerifyResponse } from '@crovly/node';