Crovly

Node.js SDK

Server-side captcha token verification for Node.js.

Installation

npm install @crovly/node

Zero 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?)

ParameterTypeDefaultDescription
secretKeystringYour API key (required)
options.baseUrlstringhttps://api.crovly.comAPI base URL
options.timeoutnumber10000Request timeout in ms

crovly.verify(token, options?)

ParameterTypeRequiredDescription
tokenstringYesToken from the widget
options.expectedIpstringNoIP 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 ClassDescription
AuthenticationErrorInvalid or missing API key (401)
ValidationErrorInvalid request data (400)
RateLimitErrorRate limit exceeded (429)
TimeoutErrorRequest timed out
NetworkErrorNetwork connectivity issue

TypeScript

Full type definitions included:

import type { CrovlyOptions, VerifyOptions, VerifyResponse } from '@crovly/node';

On this page