Skip to content

Captcha libraries comparison

How @rozie-ui/captcha compares to the existing CAPTCHA wrappers. Every provider — Google reCAPTCHA, hCaptcha, Cloudflare Turnstile — ships a framework-agnostic vanilla-JS widget; each wrapper exists only to inject the provider script, render the widget into an element, surface its config as props, and forward the verify/expire/error callbacks. Because that glue is rewritten per provider × per framework, the ecosystem is a sprawl of small, independently-versioned packages — and crucially, almost none is multi-provider: switching from reCAPTCHA to Turnstile means swapping libraries, not flipping a prop.

Research snapshot: 2026-06. Versions and the wrapper landscape move; treat them as of that date.

The wrappers at a glance

FrameworkreCAPTCHAhCaptchaTurnstileFriendlyMulti-provider?
Reactreact-google-recaptcha@hcaptcha/react-hcaptchareact-turnstile / @marsidev/react-turnstile@friendlycaptcha/react-widget❌ separate libs
Vuevue-recaptcha / vue3-recaptcha2@hcaptcha/vue3-hcaptchavue-turnstile(thin / community)❌ separate libs
Sveltesvelte-recaptcha-v2(thin / community)svelte-turnstile(community)❌ separate libs
Angularngx-captcha / ng-recaptcha(community)ngx-turnstile(community)⚠️ partial (ngx-captcha)
Solid(community / hand-roll)(none)solid-turnstile(none)❌ mostly absent
Lit(none)(none)(none)(none)❌ nothing
Rozieone provider prop

The pattern: React, Vue, Svelte, and Angular each have reasonable single-provider wrappers, but a developer who wants to let their app switch providers — or who simply wants the same component API regardless of provider — has to maintain several different dependencies with several different prop shapes and event names. Solid is sparsely served and Lit has nothing. Rozie ships one source to all six frameworks, with a single API across all four providers.

For the scoreless, widget-less reCAPTCHA v3, Rozie ships a sibling RecaptchaV3 component (same package, named export) — an imperative-first execute(action) → Promise<token> surface, again one source across all six frameworks.

Feature matrix

Cell legend: = documented out-of-the-box · = not supported · ⚠️ = partial / consumer-glue-required.

CapabilityPer-framework reCAPTCHA wrappersPer-framework hCaptcha/Turnstile wrappers@rozie-ui/captcha
Inject provider script (singleton)✅ shared globalThis loader
Render widget into element
Provider-switchable (one component)provider prop (4 providers)
Friendly Captcha provider⚠️ separate / sparse⚠️ separate / sparseprovider="friendly" (CDN, no peer)
reCAPTCHA v3 (scoreless)⚠️ separate lib⚠️ separate lib✅ sibling RecaptchaV3 component
Two-way token binding⚠️ via onChange⚠️ via callbacktoken model
verify / expire / error events✅ unified { token, provider }
Imperative reset / execute / getResponse⚠️ via ref, names vary⚠️ via ref, names vary✅ uniform handle, all 6 targets
Invisible / programmatic challenge⚠️ provider-specific⚠️ provider-specificsize="invisible" + execute()
Angular ControlValueAccessor⚠️ some⚠️ some✅ automatic (single model)
Same API across all 6 frameworks✅ one .rozie source
Same API across all 3 providers

What Rozie does not do

  • It is not a CAPTCHA itself — it wraps the providers' own widgets, which still do the bot-detection in their iframes. You still need a site key, and you still verify the token server-side against the provider's siteverify endpoint.
  • ALTCHA — the privacy-first, self-hostable alternative — is a web component, a different integration shape than the script-tag explicit-render contract here. Cleanly consuming a foreign web component across all six targets needs a compiler capability Rozie does not yet have, so ALTCHA is the sole remaining deferred provider.

Cross-references

Pre-v1.0 — internal monorepo.