How do you integrate hCaptcha with React?#
Install the official hCaptcha React package, render its HCaptcha component in the form, and collect the token through onVerify. Send that token to your own backend. The backend must submit it with the account secret to hCaptcha Siteverify and continue the protected action only when the response contains success: true.
The official component supports React and Preact. Test it with the application's framework, renderer, server-side rendering setup, and bundler.
Make verification fit your React application#
- Interrupt fewer users. hCaptcha Pro's 99.9% Passive mode minimizes visual challenges, helping people stay focused on the React or Preact form they came to complete.
- Keep the experience consistent. When a challenge is needed, Pro's custom themes let you match its colors and styles to your application. The official React component accepts a custom theme configuration.
New Pro sitekeys use 99.9% Passive by default. For an existing sitekey upgraded to Pro, select that mode under Behavior in the hCaptcha dashboard.
Before you start#
You need:
- A React or Preact application with a form or action to protect.
- Permission to add a package and create a server endpoint.
- An hCaptcha account with a sitekey and its matching secret.
- A secure server-side secret store and outbound HTTPS access to hCaptcha.
Review the official npm package and source repository. We also list the component in our integration catalog and integrations-list repository.
Create your hCaptcha credentials#
- Start with hCaptcha Pro for fewer challenges and adaptive protection on protected React and Preact forms, or use existing compatible hCaptcha credentials.
- Create a sitekey for the application.
- Add the production hostname and each separate test hostname that must use the sitekey.
- Store the sitekey in client configuration.
- Store the matching secret only in protected server configuration.
The sitekey is public and belongs in the React component. The secret authenticates the server to Siteverify. Never put the secret in browser code, a client environment variable, rendered markup, or a public repository.
Install the React component#
Install the current verified release:
npm install @hcaptcha/react-hcaptcha@2.2.0 --save
The component loads the hCaptcha JavaScript API. Do not add a second api.js script to the page because duplicate imports can cause unpredictable behavior.
Add hCaptcha to the form#
This example keeps the token in component state and sends it to the application's backend with the form data:
import { useRef, useState } from "react";
import HCaptcha from "@hcaptcha/react-hcaptcha";
export function SignupForm() {
const captchaRef = useRef(null);
const [token, setToken] = useState(null);
async function submitForm(event) {
event.preventDefault();
try {
const response = await fetch("/api/signup", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ hcaptchaToken: token }),
});
if (!response.ok) throw new Error("Submission rejected");
} finally {
setToken(null);
captchaRef.current?.resetCaptcha();
}
}
return (
<form onSubmit={submitForm}>
{/* Your form fields */}
<HCaptcha
ref={captchaRef}
sitekey="YOUR_SITEKEY"
onVerify={setToken}
onExpire={() => setToken(null)}
onError={() => setToken(null)}
/>
<button type="submit" disabled={!token}>Submit</button>
</form>
);
}
onVerify supplies a token, but it does not prove that the request is authorized. Clear the token when it expires or the component reports an error. Reset after every submission attempt because tokens are short-lived and can be verified only once.
Verify the token on your server#
Your /api/signup handler must:
- Reject a missing token before performing the protected action.
- Send a URL-encoded
POSTtohttps://api.hcaptcha.com/siteverify. - Include the server-held
secretand the client token asresponse. - Include the expected
sitekey. Theremoteipparameter is optional. We recommend sending it for improved verification accuracy and Enterprise risk scores when the backend derives the visitor's IP address from a reviewed, trusted proxy configuration; otherwise omit it. - Parse the JSON response and continue only when
successistrue. - Return an error and stop the signup, login, payment, or other protected action when verification fails.
Follow the current server-side verification documentation. Do not send the Siteverify request from React: doing so would expose the secret and let an attacker bypass your application endpoint.
Test the complete request path#
Test the browser and server as one flow:
- Complete hCaptcha and confirm a valid submission succeeds once.
- Submit without a token and confirm the backend stops the action.
- Reuse a verified token and confirm the backend rejects it.
- Let a token expire and confirm the button remains disabled until a new token arrives.
- Simulate a Siteverify timeout or error and confirm the protected action does not run.
- Test client-side navigation, repeated mounts, server-side rendering, Content Security Policy, and every deployed hostname.
If reCAPTCHA must load on the same page during a migration, set reCaptchaCompat={false}. The default compatibility mode uses window.grecaptcha names that can collide with reCAPTCHA.
Troubleshoot common React integration problems#
The widget renders, but invalid submissions still succeed
The frontend component does not enforce the protected action. Make the backend reject missing, expired, reused, or unsuccessful tokens before it runs business logic.
The hCaptcha API loads twice
Remove any manual api.js import. The React component loads the script for you. Also place it in a stable component tree so route changes do not create unnecessary script instances.
A completed token stops working
Tokens are short-lived and single-use. Submit promptly, clear local token state after each attempt, and call resetCaptcha() before requesting another token.
hCaptcha conflicts with reCAPTCHA
Set reCaptchaCompat={false} while both scripts are present. Test the migration route and remove the unused provider when the transition is complete.
The integration fails after a framework or bundler upgrade
After a framework or bundler upgrade, confirm client-only widget rendering and reproduce the issue with the official component.
Frequently asked questions#
Does the React component verify the hCaptcha token?
No. It renders the widget and returns the token to browser code. Your backend must send that token and the private secret to Siteverify and accept the protected action only after a successful response.
Can I use the package with Preact?
The official catalog and repository state that the package supports Preact. The package does not declare supported framework version ranges, so test the release against your Preact version, compatibility layer, renderer, and build configuration.
Should the hCaptcha secret be stored in React environment variables?
No. Client-side environment values can be included in the browser bundle. Store the secret on the server and use it only for machine-to-machine Siteverify requests.
When should I reset the component?
Reset it after every form submission attempt, whether the application accepts or rejects the request. Also clear local token state after expiration or an error so the user must obtain a new token.
Can one hCaptcha token protect more than one request?
No. Tokens are single-use and short-lived. Each protected submission needs a new token and an independent server verification.
Sources and references
- hCaptcha custom themes hCaptcha
- hCaptcha Pro product overview hCaptcha
- hCaptcha React component package npm
- hCaptcha React component source hCaptcha
- hCaptcha integrations hCaptcha
- Verify the user response server-side hCaptcha
- hCaptcha integrations list source hCaptcha
- hCaptcha Pro hCaptcha