Skip to main content

Add bot protection to your custom sign-up flow

Warning

This guide is for users who want to build a . To use a prebuilt UI, use the Account Portal pages or prebuilt components.

Clerk provides the ability to add a CAPTCHA widget to your sign-up flows to protect against bot sign-ups. The <SignUp /> component handles this flow out-of-the-box. However, if you're building a custom user interface, this guide will show you how to add the CAPTCHA widget to your custom sign-up flow.

Enable bot sign-up protection

  1. In the Clerk Dashboard, navigate to the Attack protection page.
  2. Enable the Bot sign-up protection toggle.

Warning

If your application previously had the Invisible CAPTCHA type selected, it's highly recommended to switch to the Smart option, as the Invisible option is deprecated. For newer applications, CAPTCHA type options are no longer shown in the Dashboard. Bot protection uses the Smart option by default and is enabled by turning on the Bot sign-up protection toggle only.

Note

In Expo apps, the CAPTCHA widget renders only on web. On iOS and Android, Clerk skips the browser CAPTCHA challenge, so no CAPTCHA widget or invisible fallback is rendered on native devices.

To render the CAPTCHA widget in your custom sign-up form, you need to include the <View nativeID="clerk-captcha" /> element by the time you call signUp.create(). This element acts as a placeholder onto which the widget will be rendered.

If this element is not found, the SDK will transparently fall back to an invisible widget in order to avoid breaking your sign-up flow.

Tip

The invisible widget fallback automatically blocks suspected bot traffic without offering users falsely detected as bots with an opportunity to prove otherwise. Therefore, it's strongly recommended that you ensure the <View nativeID="clerk-captcha" /> element exists in your sign-up screen.

The following example shows how to support the CAPTCHA widget:

<View>
  <Text>Sign up</Text>
  <TextInput
    autoCapitalize="none"
    keyboardType="email-address"
    value={emailAddress}
    onChangeText={setEmailAddress}
    placeholder="Enter email address"
  />
  <TextInput
    secureTextEntry
    value={password}
    onChangeText={setPassword}
    placeholder="Enter password"
  />

  {/* Clerk's CAPTCHA widget */}
  <View nativeID="clerk-captcha" />

  <Pressable onPress={handleSubmit}>
    <Text>Continue</Text>
  </Pressable>
</View>

For custom flows on Expo web, customize the CAPTCHA widget by passing dataSet to the <View nativeID="clerk-captcha" /> element. React Native Web renders these values as data-cl-* attributes.

<View
  nativeID="clerk-captcha"
  dataSet={{ clTheme: 'dark', clSize: 'flexible', clLanguage: 'es-ES' }}
/>

Note

dataSet is a React Native Web prop and isn't part of React Native's View types. In a strict TypeScript project, cast the props or augment ViewProps to set it.

Feedback

What did you think of this content?

Last updated on