Qwik
Using better-captcha with Qwik
Installation
npm i @better-captcha/qwikBasic Usage
import { component$ } from "@builder.io/qwik";
import { ReCaptcha } from "@better-captcha/qwik/provider/recaptcha";
export default component$(() => {
return <ReCaptcha sitekey="your-site-key" />;
});Imperative Handle
Qwik uses the useCaptchaController hook to access the imperative handle via a controller pattern that works with Qwik's serialization model.
import { component$ } from "@builder.io/qwik";
import { useCaptchaController } from "@better-captcha/qwik";
import { ReCaptcha, type ReCaptchaHandle } from "@better-captcha/qwik/provider/recaptcha";
export default component$(() => {
const controller = useCaptchaController<ReCaptchaHandle>();
return (
<>
<ReCaptcha
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
controller={controller}
/>
<button onClick$={() => controller.value?.execute()}>Execute</button>
<button onClick$={() => controller.value?.reset()}>Reset</button>
<button onClick$={() => console.log(controller.value?.getResponse())}>Log response</button>
</>
);
});The handle is available once the widget is ready. Always use optional chaining (?.) when calling methods since the controller may not be initialized yet.
Lifecycle Callbacks
All captcha components support three lifecycle callbacks via QRL props. Note the $ suffix required by Qwik for serializable functions.
import { component$, $ } from "@builder.io/qwik";
import { useCaptchaController } from "@better-captcha/qwik";
import { ReCaptcha, type ReCaptchaHandle } from "@better-captcha/qwik/provider/recaptcha";
export default component$(() => {
const controller = useCaptchaController<ReCaptchaHandle>();
const handleReady$ = $((handle: ReCaptchaHandle) => {
console.log("Captcha is ready", handle);
});
const handleSolve$ = $((token: string) => {
console.log("Captcha solved with token:", token);
// Send token to your backend for verification
});
const handleError$ = $((error: Error) => {
console.error("Captcha error:", error);
});
return (
<ReCaptcha
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
controller={controller}
onReady$={handleReady$}
onSolve$={handleSolve$}
onError$={handleError$}
/>
);
});| Callback | Parameters | Description |
|---|---|---|
onReady$ | (handle: Handle) => void | Called when the widget is rendered and ready (receives handle) |
onSolve$ | (token: string) => void | Called when the challenge is solved with the response token |
onError$ | (error: Error) => void | Called when an error occurs during initialization or solving |
Manual Rendering
By default, captchas automatically render on mount. For more control, disable auto-rendering and trigger it manually.
import { component$ } from "@builder.io/qwik";
import { useCaptchaController } from "@better-captcha/qwik";
import { ReCaptcha } from "@better-captcha/qwik/provider/recaptcha";
export default component$(() => {
const controller = useCaptchaController();
return (
<>
<ReCaptcha
sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"
controller={controller}
autoRender={false}
/>
<button onClick$={async () => await controller.value?.render()}>Show Captcha</button>
</>
);
});Common Props
| Prop | Type | Required | Description |
|---|---|---|---|
sitekey | string | ✅ | Your provider's site key |
controller | Signal | ❌ | Controller from useCaptchaController() for imperative access |
options | object | ❌ | Provider-specific configuration options |
autoRender | boolean | ❌ | Whether to render automatically on mount (default: true) |
scriptOptions | object | ❌ | Script loading configuration (see Script Options) |
onReady$ | QRL | ❌ | Callback when widget is ready |
onSolve$ | QRL | ❌ | Callback when challenge is solved |
onError$ | QRL | ❌ | Callback when an error occurs |
Handle Methods
All providers implement these methods on the handle:
Prop
Type
Available Providers
| Provider | Import Path |
|---|---|
| ReCaptcha | @better-captcha/qwik/provider/recaptcha |
| HCaptcha | @better-captcha/qwik/provider/hcaptcha |
| Turnstile | @better-captcha/qwik/provider/turnstile |
| Friendly Captcha | @better-captcha/qwik/provider/friendly-captcha |
| Private Captcha | @better-captcha/qwik/provider/private-captcha |
| Captcha Fox | @better-captcha/qwik/provider/captcha-fox |
| Prosopo | @better-captcha/qwik/provider/prosopo |
| CapWidget | @better-captcha/qwik/provider/cap-widget |
See the Provider Documentation for provider-specific options and configuration.