React SDK
Use Crovly captcha in React and Next.js applications.
Installation
npm install @crovly/reactBasic 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
| Prop | Type | Default | Description |
|---|---|---|---|
siteKey | string | — | Your public site key (required) |
apiUrl | string | https://api.crovly.com | API endpoint |
theme | 'light' | 'dark' | 'auto' | 'auto' | Widget theme |
size | 'normal' | 'managed' | 'invisible' | 'normal' | Widget mode |
lang | string | Browser default | Language code |
badge | boolean | true | Show "Protected by Crovly" badge |
primaryColor | string | — | Custom accent color (hex, e.g. #6366f1) |
responseFieldName | string | 'crovly-token' | Hidden input field name |
onVerify | (token: string) => void | — | Called on successful verification |
onError | (code: string, message: string) => void | — | Called on error |
onExpire | () => void | — | Called 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
| Method | Returns | Description |
|---|---|---|
reset() | void | Reset the widget and re-run verification |
getResponse() | string | null | Get the current token, or null if not verified |
remove() | void | Remove 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';