@dynamic-labs-sdk/react-native-captcha
v1.38.0
Published
Captcha challenge widgets for React Native apps using Dynamic.
Readme
@dynamic-labs-sdk/react-native-captcha
Captcha challenge widgets for React Native apps using Dynamic.
Provides self-contained HCaptchaChallenge and TurnstileChallenge components that render their provider's widget in a react-native-webview and return the captcha token over a postMessage bridge. Pass the token to @dynamic-labs-sdk/client's setCaptchaToken before sign-in methods that require captcha.
Installation
pnpm add @dynamic-labs-sdk/react-native-captchaRequires @dynamic-labs-sdk/client and react-native-webview.
Usage
Read the active provider and site key from getCaptchaSettings, then render the matching challenge component.
import { useState } from 'react';
import { View, Button } from 'react-native';
import { CaptchaProviderEnum, getCaptchaSettings, setCaptchaToken } from '@dynamic-labs-sdk/client';
import { HCaptchaChallenge, TurnstileChallenge } from '@dynamic-labs-sdk/react-native-captcha';
function SignInScreen() {
const [captchaReady, setCaptchaReady] = useState(false);
const settings = getCaptchaSettings();
const siteKey = settings?.siteKey;
const handleSignIn = async () => {
// sendEmailOTP, auth.wallet.connect, etc.
};
if (!settings || !siteKey) {
return <Button title="Sign in" onPress={handleSignIn} />;
}
const handleToken = (token: string) => {
setCaptchaToken({ captchaToken: token });
setCaptchaReady(true);
};
const Challenge =
settings.provider === CaptchaProviderEnum.Hcaptcha
? HCaptchaChallenge
: TurnstileChallenge;
return (
<View>
<Challenge
baseUrl="https://your-whitelisted-origin.com"
siteKey={siteKey}
onToken={handleToken}
onError={(error) => console.error(error.message)}
/>
<Button title="Sign in" disabled={!captchaReady} onPress={handleSignIn} />
</View>
);
}The baseUrl prop is the origin the widget document is served under. hCaptcha and Turnstile site keys only render on whitelisted hostnames, so set it to a domain you have added to your provider's site configuration.
Components
| Component | Provider |
| --------- | -------- |
| HCaptchaChallenge | hCaptcha |
| TurnstileChallenge | Cloudflare Turnstile |
Both components accept baseUrl, siteKey, onToken, onError, and an optional style prop. onToken fires once when the user solves the challenge; onError fires once on challenge error, token expiry, or WebView load failure. The returned errors are typed (HCaptchaError / TurnstileError) so you can branch on error instanceof HCaptchaError or inspect error.message.
Use the style prop to override the default height, border radius, or other container styles to match your app's design.
Retrying a challenge
onToken and onError each fire at most once per mounted widget. If you need to let the user retry after a challenge error or token expiry, unmount and remount the component, for example by incrementing a React key:
const [attemptKey, setAttemptKey] = useState(0);
<Challenge
key={attemptKey}
baseUrl="https://your-whitelisted-origin.com"
siteKey={siteKey}
onToken={handleToken}
onError={(error) => {
console.error(error.message);
setAttemptKey((k) => k + 1);
}}
/>