🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@captigo/nextjs

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@captigo/nextjs

Next.js App Router helpers for Captigo — request parsing, client IP, and route-handler verification

latest
Source
npmnpm
Version
0.2.0
Version published
Maintainers
1
Created
Source

@captigo/nextjs

Next.js App Router helpers for Captigo — parse Request, resolve client IP, verify with any CaptchaAdapter.

Uses the Web Request API only (no runtime dependency on next). Pair with @captigo/react and an adapter such as @captigo/turnstile on the client.

Installation

npm install @captigo/nextjs @captigo/turnstile

@captigo/core is installed transitively. next ≥ 14 is an optional peer (declared for version clarity; helpers work anywhere Request is available).

App Router — route handler

The most common pattern: a POST endpoint that receives the token from a form and verifies it before taking any action.

// app/api/submit/route.ts
import { verifyCaptchaFromRequest, CaptchaError } from "@captigo/nextjs";
import { turnstile } from "@captigo/turnstile";

const adapter = turnstile({ siteKey: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY! });

export async function POST(request: Request) {
  let result;
  try {
    result = await verifyCaptchaFromRequest(
      request,
      adapter,
      process.env.TURNSTILE_SECRET!,
    );
  } catch (err) {
    if (err instanceof CaptchaError) {
      // Token was missing from the body, or the provider network call failed.
      return Response.json({ error: err.message }, { status: 400 });
    }
    throw err;
  }

  if (!result.success) {
    return Response.json({ error: "CAPTCHA verification failed" }, { status: 400 });
  }

  // Token is verified — proceed with the protected action.
  return Response.json({ ok: true });
}

Note on field names. verifyCaptchaFromRequest looks for a "token" field by default. If your form uses a different name (e.g. "cf-turnstile-response" from Turnstile's auto-injected hidden input), pass it via options.fieldName.

Client-side (App Router)

Use @captigo/react and @captigo/turnstile on the client as usual. No changes are needed — @captigo/nextjs is a server-only package.

// app/contact/page.tsx
"use client";
import { Captcha } from "@captigo/react";
import { turnstile } from "@captigo/turnstile";
import { useState } from "react";

const adapter = turnstile({ siteKey: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY! });

export default function ContactPage() {
  const [token, setToken] = useState<string | null>(null);

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!token) return;

    await fetch("/api/submit", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ token, message: "Hello" }),
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <Captcha adapter={adapter} onSuccess={(t) => setToken(t.value)} />
      <button type="submit" disabled={!token}>Send</button>
    </form>
  );
}

API

verifyCaptchaFromRequest(request, adapter, secretKey, options?)

Extracts the CAPTCHA token from the request body, resolves the client IP from standard headers, and calls adapter.verify().

import { verifyCaptchaFromRequest } from "@captigo/nextjs";

const result = await verifyCaptchaFromRequest(request, adapter, secretKey, {
  fieldName: "token",   // default — the body field that holds the token
  forwardIp: true,      // default — passes client IP to the provider
});

Throws CaptchaError when:

  • The token field is absent from the request body.
  • The provider's network request fails.

Returns VerifyResult — check result.success to decide whether to accept the submission.

captchaTokenFromRequest(request, fieldName?)

Extracts the raw token string from a request body. Tries JSON first, then FormData/URL-encoded. Returns null when the field is absent or empty — never throws on parse failure.

import { captchaTokenFromRequest } from "@captigo/nextjs";

// Use this when you need the token separately before calling adapter.verify().
const token = await captchaTokenFromRequest(request, "cf-turnstile-response");
if (!token) {
  return Response.json({ error: "Missing CAPTCHA token" }, { status: 400 });
}

const result = await adapter.verify(token, process.env.TURNSTILE_SECRET!);

clientIpFromRequest(request)

Resolves the client IP from standard CDN and proxy headers. Checks in order:

  • CF-Connecting-IP (Cloudflare)
  • X-Forwarded-For (first address in the list)
  • X-Real-IP (nginx)

Returns undefined when none are present.

import { clientIpFromRequest } from "@captigo/nextjs";

const ip = clientIpFromRequest(request);
const result = await adapter.verify(token, secretKey, ip ? { remoteip: ip } : undefined);

Server Actions

verifyCaptchaFromRequest expects a Request object. Server Actions receive form data directly, not a Request, so use captchaTokenFromRequest with the raw FormData instead — or verify via a route handler.

// app/actions.ts
"use server";
import { CaptchaError } from "@captigo/nextjs";
import { turnstile } from "@captigo/turnstile";

const adapter = turnstile({ siteKey: process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY! });

export async function submitAction(formData: FormData) {
  const token = formData.get("token");
  if (typeof token !== "string" || !token) {
    throw new Error("Missing CAPTCHA token");
  }

  const result = await adapter.verify(token, process.env.TURNSTILE_SECRET!);
  if (!result.success) {
    throw new Error("CAPTCHA verification failed");
  }

  // ... proceed
}

Notes

  • No next runtime dependency. The helpers work with the standard Web Request API (available natively in Next.js App Router and Node.js 18+).
  • Server-only. Never call adapter.verify() or expose your secret key on the client.
  • Provider-agnostic. Pass any captigo adapter — turnstile(config), hcaptcha(config), recaptchaV2(config), etc.

Documentation

@captigo/react · Repository · Issues

Keywords

app-router

FAQs

Package last updated on 03 Apr 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts