Documentation

Next.js

Use the browser SDK in the client and redeem the proof token in an App Router route handler.

client component

"use client";

import { useEffect, useRef, useState } from "react";
import { createCaptcha } from "@captchacc/browser";

export default function ContactForm() {
  const slotRef = useRef(null);
  const [captcha, setCaptcha] = useState(null);

  useEffect(() => {
    if (!slotRef.current) return;
    createCaptcha(slotRef.current, {
      siteKey: "pk_live_xxx",
      apiBase: "https://captcha.cc"
    }).then(setCaptcha);
  }, []);

  async function onSubmit(event) {
    event.preventDefault();
    if (!captcha) return;

    const form = new FormData(event.currentTarget);
    const answer = String(form.get("captcha_answer") || "");
    const result = await captcha.verify(answer);
    if (!result.ok) return;

    await fetch("/api/contact", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ proofToken: result.proofToken })
    });
  }

  return (
    
); }

route handler

export async function POST(request: Request) {
  const body = await request.json();

  const verifyResponse = await fetch("https://captcha.cc/v1/siteverify", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      secret_key: process.env.CAPTCHA_CC_SECRET_KEY,
      proof_token: body.proofToken
    })
  });

  const verify = await verifyResponse.json();
  if (!verify.success) {
    return Response.json({ error: "captcha verification failed", verify }, { status: 400 });
  }

  return Response.json({ ok: true });
}