Crovly

React SDK

Use Crovly captcha in React and Next.js applications.

Installation

npm install @crovly/react

Basic Usage

import { CrovlyCaptcha } from '@crovly/react';

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

  return (
    <form onSubmit={handleSubmit}>
      <CrovlyCaptcha
        siteKey="YOUR_SITE_KEY"
        onVerify={(token) => setToken(token)}
      />
      <button type="submit" disabled={!token}>
        Submit
      </button>
    </form>
  );
}

Props

PropTypeDefaultDescription
siteKeystringYour public site key (required)
apiUrlstringhttps://api.crovly.comAPI endpoint
theme'light' | 'dark' | 'auto''auto'Widget theme
size'normal' | 'managed' | 'invisible''normal'Widget mode
langstringBrowser defaultLanguage code
badgebooleantrueShow "Protected by Crovly" badge
primaryColorstringCustom accent color (hex, e.g. #6366f1)
responseFieldNamestring'crovly-token'Hidden input field name
onVerify(token: string) => voidCalled on successful verification
onError(code: string, message: string) => voidCalled on error
onExpire() => voidCalled when token expires

useCrovly Hook

For programmatic control, use the useCrovly hook.

import { CrovlyCaptcha, useCrovly } from '@crovly/react';

function MyForm() {
  const { reset, getResponse } = useCrovly();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    const token = getResponse();
    if (!token) return;

    const res = await fetch('/api/submit', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token }),
    });

    if (!res.ok) {
      // Reset captcha on failure so user can retry
      reset();
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <CrovlyCaptcha siteKey="YOUR_SITE_KEY" />
      <button type="submit">Submit</button>
    </form>
  );
}

Hook Methods

MethodReturnsDescription
reset()voidReset the widget and re-run verification
getResponse()string | nullGet the current token, or null if not verified
remove()voidRemove the widget and clean up

Next.js App Router

The Crovly widget uses browser APIs, so it must run as a client component.

// app/contact/page.tsx
import { ContactForm } from './contact-form';

export default function ContactPage() {
  return (
    <main>
      <h1>Contact Us</h1>
      <ContactForm />
    </main>
  );
}
// app/contact/contact-form.tsx
'use client';

import { useState } from 'react';
import { CrovlyCaptcha } from '@crovly/react';

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

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    const formData = new FormData(e.currentTarget);

    const res = await fetch('/api/contact', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        name: formData.get('name'),
        email: formData.get('email'),
        message: formData.get('message'),
        token,
      }),
    });

    if (res.ok) {
      alert('Message sent!');
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" placeholder="Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />

      <CrovlyCaptcha
        siteKey="YOUR_SITE_KEY"
        theme="auto"
        onVerify={setToken}
        onError={(code, msg) => console.error(code, msg)}
      />

      <button type="submit" disabled={!token}>
        Send Message
      </button>
    </form>
  );
}

Form Integration

The widget automatically injects a hidden input field into the parent form. If you prefer to handle the token manually with onVerify, you can disable the hidden input:

<CrovlyCaptcha
  siteKey="YOUR_SITE_KEY"
  responseFieldName=""
  onVerify={(token) => {
    // handle token manually
    document.cookie = `crovly-token=${token}; path=/`;
  }}
/>

For standard form submissions (non-AJAX), the hidden input works automatically:

<form action="/api/submit" method="POST">
  <input name="email" type="email" required />
  <CrovlyCaptcha siteKey="YOUR_SITE_KEY" />
  <button type="submit">Subscribe</button>
</form>

The token will be submitted as crovly-token in the form data.

TypeScript

The package includes full TypeScript definitions. All props and hook return types are exported:

import type { CrovlyCaptchaProps, UseCrovlyReturn } from '@crovly/react';

On this page