{"id":23867136,"url":"https://github.com/hcaptcha/hcaptcha-android-sdk","last_synced_at":"2025-04-06T06:07:42.400Z","repository":{"id":37862301,"uuid":"331998522","full_name":"hCaptcha/hcaptcha-android-sdk","owner":"hCaptcha","description":"Android SDK for hCaptcha","archived":false,"fork":false,"pushed_at":"2025-03-24T01:11:11.000Z","size":10089,"stargazers_count":87,"open_issues_count":5,"forks_count":42,"subscribers_count":16,"default_branch":"main","last_synced_at":"2025-03-30T05:06:26.174Z","etag":null,"topics":["android","hcaptcha","sdk-android"],"latest_commit_sha":null,"homepage":"https://www.hcaptcha.com","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hCaptcha.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-22T16:17:00.000Z","updated_at":"2025-03-29T19:31:57.000Z","dependencies_parsed_at":"2024-06-03T21:03:12.682Z","dependency_job_id":"7a426237-f048-4c4b-8765-32b620cbb41a","html_url":"https://github.com/hCaptcha/hcaptcha-android-sdk","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hCaptcha%2Fhcaptcha-android-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hCaptcha%2Fhcaptcha-android-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hCaptcha%2Fhcaptcha-android-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hCaptcha%2Fhcaptcha-android-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hCaptcha","download_url":"https://codeload.github.com/hCaptcha/hcaptcha-android-sdk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247441049,"owners_count":20939239,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","hcaptcha","sdk-android"],"created_at":"2025-01-03T10:14:51.302Z","updated_at":"2025-04-06T06:07:42.375Z","avatar_url":"https://github.com/hCaptcha.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Android SDK for hCaptcha\n\n![CI](https://github.com/hCaptcha/hcaptcha-android-sdk/workflows/ci/badge.svg)\n[![Release](https://jitpack.io/v/hcaptcha/hcaptcha-android-sdk.svg)](https://jitpack.io/#hcaptcha/hcaptcha-android-sdk)\n[![Minimal Android OS](https://img.shields.io/badge/Android%20OS%20-%3E=4.1-blue.svg)](https://developer.android.com/about/dashboards)\n\n###### [Installation](#installation) | [Requirements](#requirements) | [Example App](#example-app) | [Usage](#usage) | [Customization](#config-params) | [Error Handling](#error-handling) | [Debugging](#debugging-tips) | [FAQ](#faq)\n\nThis SDK provides a wrapper for [hCaptcha](https://www.hcaptcha.com). It is a drop-in replacement for the SafetyNet reCAPTCHA API. You will need to configure a `site key` and a `secret key` from your hCaptcha account in order to use it.\n\n\n## Installation\n\n\u003cpre\u003e\n// Register JitPack Repository inside the root build.gradle file\nrepositories {\n    \u003cb\u003emaven { url 'https://jitpack.io' }\u003c/b\u003e \n}\n// Add hCaptcha sdk dependency inside the app's build.gradle file\ndependencies {\n    // For Android View\n    \u003cb\u003eimplementation 'com.github.hCaptcha.hcaptcha-android-sdk:sdk:x.y.z'\u003c/b\u003e\n    // For Jetpack Compose\n    \u003cb\u003eimplementation 'com.github.hCaptcha.hcaptcha-android-sdk:compose-sdk:x.y.z'\u003c/b\u003e\n}\n\u003c/pre\u003e\n\n*Note: replace `x.y.z` with one from [Release](https://github.com/hCaptcha/hcaptcha-android-sdk/releases) (e.g. `1.0.0`).*\n\n### Legacy (versions \u003c 5.0)\n\n\u003cpre\u003e\n// Register JitPack Repository inside the root build.gradle file\nrepositories {\n    \u003cb\u003emaven { url 'https://jitpack.io' }\u003c/b\u003e \n}\n// Add hCaptcha sdk dependency inside the app's build.gradle file\ndependencies {\n    \u003cb\u003eimplementation 'com.github.hcaptcha:hcaptcha-android-sdk:x.y.z'\u003c/b\u003e\n}\n\u003c/pre\u003e\n\n## Requirements\n\n| Platform   | Requirements                                 |\n|------------|----------------------------------------------|\n| Android OS | :white_check_mark: \u003e= 4.1 (Android API 16)   |\n| Wear OS    | :heavy_multiplication_x:                     |\n\n## Example App\n\nThe current repository comes with an example Android application demonstrating 3 different hCaptcha usage patterns. \n\nSee the code example below along with the possible customization to enable human verification in your Android application.\n\n\u003cimg src=\"/assets/hcaptcha-invisible-example.gif\" alt=\"invisible hcaptcha example\" width=\"300px\"/\u003e\n\n## Usage\n\nThere are multiple ways to run a hCaptcha human verification. See the below snippet for the overall flow.\n\n```java\nimport com.hcaptcha.sdk.*;\nimport com.hcaptcha.sdk.tasks.*;\n\n// =================================================\n// 1. Initialize a client using the current activity\nfinal HCaptcha hCaptcha = HCaptcha.getClient(this);\n\n// =================================================\n// 2. Add the desired listeners\nhCaptcha\n  .addOnSuccessListener(new OnSuccessListener\u003cHCaptchaTokenResponse\u003e() {\n    @Override\n    public void onSuccess(HCaptchaTokenResponse response) {\n        // Successul verification. The resulting token must be passed to your backend to be validated.\n        String userResponseToken = response.getTokenResult();\n        Log.d(\"hCaptcha\", \"hCaptcha success. Token: \" + userResponseToken\");\n    }\n  })\n  .addOnFailureListener(new OnFailureListener() {\n    @Override\n    public void onFailure(HCaptchaException e) {\n        // Error handling here: trigger another verification, display a toast, etc.\n        Log.d(\"hCaptcha\", \"hCaptcha failed: \" + e.getMessage() + \"(\" + e.getStatusCode() + \")\");\n    }\n  })\n  .addOnOpenListener(new OnOpenListener() {\n    @Override\n    public void onOpen() {\n        // Usefull for analytics purposes\n        Log.d(\"hCaptcha\", \"hCaptcha is now visible.\");\n    }\n  });\n\n// =================================================\n// 3. Trigger the verification process which may or may not require user input. \n//    It depends on the sitekey difficulty setting and the hCaptcha client configuration.\n// 3.1 Optionaly, setup the client to pre-warm the assets.\n//     It helps speeding up the actual verification process by having the assets locally already.\nhCaptcha.setup(/* args */);\n// 3.2 Invoke the actual verification process\n//     If \"setup(/* args */)\" was used, this should be called with empty args.\nhCaptcha.verifyWithHCaptcha(/* args */).\n\n// The \"args\" for setup and verifyWithHCaptcha can be the following:\n// 1. The sitekey string.\nfinal String SITE_KEY = \"10000000-ffff-ffff-ffff-000000000001\";\nhCaptcha.setup(SITE_KEY).verifyWithHCaptcha()\n// 2. An \"HCaptchaConfig\" object which allows customization \n//    of the look and feel, the language and more. \n//    See section \"Config Params\" below.\nfinal HCaptchaConfig hCaptchaConfig = HCaptchaConfig.builder()\n        .siteKey(\"10000000-ffff-ffff-ffff-000000000001\")\n        .size(HCaptchaSize.NORMAL)\n        .theme(HCaptchaTheme.LIGHT)\n        .build();\nhCaptcha.setup(hCaptchaConfig).verifyWithHCaptcha()\n// 3. No params. Sitekey must be configured via `AndroidManifest.xml`.\nhCaptcha.setup().verifyWithHCaptcha()\n// Set sitekey in AndroidManifest.xml (required only for option 3)\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003capplication ...\u003e\n   \u003cmeta-data android:name=\"com.hcaptcha.sdk.site-key\"\n              android:value=\"YOUR_API_SITE_KEY\" /\u003e\n\u003c/application\u003e\n\u003c/manifest\u003e\n```\n\nTo remove a specific listener you may use `HCaptcha.removeOn[Success|Failure|Open]Listener(listener)`.\n\nTo remove all listeners you may use `HCaptcha.removeAllListener()`.\n\nNote ⚠️: For any sitekey that can show visual challenges, `HCaptcha.getClient(Activity)` must be called with `FragmentActivity` instance.\n\n`Activity` is allowed only when `hideDialog=true` and sitekey setting is Passive (Enterprise feature).\n\n\n```java\n...\nOnSuccessListener\u003cHCaptchaTokenResponse\u003e firstListener = new OnSuccessListener\u003cHCaptchaTokenResponse\u003e() {\n    @Override\n    public void onSuccess(HCaptchaTokenResponse response) {\n        ...\n    }\n};\nhCaptcha.addOnSuccessListener(firstListener).verifyWithHCaptcha();\n...\nOnSuccessListener\u003cHCaptchaTokenResponse\u003e secondListener = new OnSuccessListener\u003cHCaptchaTokenResponse\u003e() {\n    @Override\n    public void onSuccess(HCaptchaTokenResponse response) {\n        ...\n    }\n};\nhCaptcha.removeOnSuccessListener(firstListener)\n    .addOnSuccessListener(secondListener)\n    .verifyWithHCaptcha();\n```\n\n### For Jetpack Compose\n\n```kotlin\nimport com.hcaptcha.sdk.HCaptcha\nimport com.hcaptcha.sdk.HCaptchaException\nimport com.hcaptcha.sdk.HCaptchaTokenResponse\n\nclass HCaptchaActivity : AppCompatActivity() {\n\n    private val hCaptcha = HCaptcha.getClient(this)\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n\n        hCaptcha.setup(BuildConfig.SITE_KEY).verifyWithHCaptcha()\n        hCaptcha.addOnSuccessListener { response: HCaptchaTokenResponse -\u003e\n            val userResponseToken = response.tokenResult\n            val intent = Intent()\n            intent.putExtra(\"captcha\", userResponseToken)\n            setResult(RESULT_OK, intent)\n            finish()\n        }.addOnFailureListener { e: HCaptchaException -\u003e\n            // Error handling here: trigger another verification, display a toast, etc.\n            Log.d(\"hCaptcha\", \"hCaptcha failed: \" + e.getMessage() + \"(\" + e.getStatusCode() + \")\")\n            setResult(RESULT_CANCELED)\n            finish()\n        }.addOnOpenListener { \n            // Usefull for analytics purposes\n            Log.d(\"hCaptcha\", \"hCaptcha is now visible.\")\n        }\n    }\n}\n```\nTo fetch token data from activity in @Composable Class: \n\n```kotlin\nval intent = Intent(context, HCaptchaActivity::class.java)\n                val launcher =\n                    rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -\u003e\n                        val data: Intent? = result.data\n                        when (result.resultCode) {\n                            Activity.RESULT_OK -\u003e {\n                                data?.let {\n                                    captcha.value = data.extras?.getString(\"captcha\")?: \"\"\n                                }                        \n                            }\n                            Activity.RESULT_CANCELED -\u003e {\n                                Log.d(\"hCaptcha\", \"hCaptcha failed\")\n                            }\n                        }\n                    }\n                SideEffect {\n                    launcher.launch(intent)\n                }\n```\n\n### Memory usage (fragment lifecycle)\n\nWe cache the fragment instance inside the SDK to speed up the next HCaptcha.verifyWithHCaptcha calls.\n\nOnce you are done with verification, you can call `HCaptcha.reset()` to release all allocated resources including the strong reference to `com.hcaptcha.sdk.HCaptchaDialogFragment`.\n\nNote: If you do not call `.reset()` you will likely see a warning from tools like LeakCanary.\n\n### Good to know\n1. The listeners (`onSuccess`, `onFailure`, `onOpen`) can be called multiple times in the following cases:\n   1. the same client is used to invoke multiple verifications\n   2. the config option `resetOnTimeout(true)` is used which will automatically trigger a new verification when the current token expired. This will result in a new success or error callback.\n      * deprecated, please use [`HCaptchaConfig.retryPredicate`](#retry-failed-verification)\n   2. the config option [`HCaptchaConfig.retryPredicate`](#retry-failed-verification) is used to automatically trigger a new verification when some error occurs. If `HCaptchaConfig.retryPredicate` returns `true`, this will result in a new success or error callback.\n   3. `onFailure` with `TOKEN_TIMEOUT` will be called once the token is expired. To prevent this you can call `HCaptchaTokenResponse.markUsed` once the token is utilized. Also, you can change expiration timeout with `HCaptchaConfigBuilder.tokenExpiration(timeout)` (default 2 min.)\n\n## Config Params\n\nThe following list contains configuration properties to allows customization of the hCaptcha verification flow.\n\n| Name                          | Values/Type                                          | Required | Default                          | Description                                                                                                                                                          |\n|-------------------------------|------------------------------------------------------|----------|----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `siteKey`                     | String                                               | **Yes**  | -                                | This is your sitekey, this allows you to load challenges. If you need a sitekey, please visit [hCaptcha](https://www.hcaptcha.com), and sign up to get your sitekey. |\n| `size`                        | Enum                                                 | No       | INVISIBLE                        | This specifies the \"size\" of the checkbox component. By default, the checkbox is invisible and the challenge is shown automatically.                                 |\n| `orientation`                 | Enum                                                 | No       | PORTRAIT                         | This specifies the \"orientation\" of the challenge.                                                                                                                   |\n| `theme`                       | Enum                                                 | No       | LIGHT                            | hCaptcha supports light, dark, and contrast themes.                                                                                                                  |\n| `locale`                      | String (ISO 639-1 code)                              | No       | AUTO                             | You can enforce a specific language or let hCaptcha auto-detect the local language based on user's device.                                                           |\n| `resetOnTimeout`              | Boolean                                              | No       | False                            | (DEPRECATED, use `retryPredicate`) Automatically reload to fetch new challenge if user does not submit challenge. (Matches iOS SDK behavior.)                        |\n| `retryPredicate`              | Lambda\u003csup\u003e[*](#retry-predicate-serialization)\u003c/sup\u003e | No       | -                                | Automatically trigger a new verification when some error occurs.                                                                                                     |\n| `jsSrc`                       | String (URL)                                         | No       | https://js.hcaptcha.com/1/api.js | See Enterprise docs.                                                                                                                                                 |\n| `sentry`                      | Boolean                                              | No       | True                             | See Enterprise docs.                                                                                                                                                 |\n| `rqdata`                      | String                                               | No       | -                                | See Enterprise docs.                                                                                                                                                 |\n| `apiEndpoint`                 | String (URL)                                         | No       | -                                | (DEPRECATED, use `jsSrc`) See Enterprise docs.                                                                                                                       |\n| `endpoint`                    | String (URL)                                         | No       | -                                | See Enterprise docs.                                                                                                                                                 |\n| `reportapi`                   | String (URL)                                         | No       | -                                | See Enterprise docs.                                                                                                                                                 |\n| `assethost`                   | String (URL)                                         | No       | -                                | See Enterprise docs.                                                                                                                                                 |\n| `imghost`                     | String (URL)                                         | No       | -                                | See Enterprise docs.                                                                                                                                                 |\n| `customTheme`                 | Stringified JSON                                     | No       | -                                | See Enterprise docs.                                                                                                                                                 |\n| `host`                        | String (URL)                                         | No       | -                                | See Enterprise docs.                                                                                                                                                 |\n| `loading`                     | Boolean                                              | No       | True                             | Show or hide the loading dialog.                                                                                                                                     |\n| `hideDialog`                  | Boolean                                              | No       | False                            | To be used in combination with a passive sitekey when no user interaction is required. See Enterprise docs.                                                          |\n| `tokenExpiration`             | long                                                 | No       | 120                              | hCaptcha token expiration timeout (seconds).                                                                                                                         |\n| `diagnosticLog`               | Boolean                                              | No       | False                            | Emit detailed console logs for debugging                                                                                                                             |\n| `disableHardwareAcceleration` | Boolean                                              | No       | True                             | Disable WebView hardware acceleration                                                                                                                                |\n\n### Config Examples\n\n1. Ask the user to complete a challenge without requiring a previous checkbox tap.\n\n```java\nfinal HCaptchaConfig config = HCaptchaConfig.builder()\n        .siteKey(YOUR_API_SITE_KEY)\n        .size(HCaptchaSize.INVISIBLE)\n        .build();\n```\n\n2. Set a specific language, use a dark theme and a compact checkbox.\n```java\nfinal HCaptchaConfig config = HCaptchaConfig.builder()\n                .siteKey(\"YOUR_API_SITE_KEY\")\n                .locale(\"ro\")\n                .size(HCaptchaSize.COMPACT)\n                .theme(HCaptchaTheme.DARK)\n                .build();\n```\n\n## Error handling\n\nIn some scenarios in which the human verification process cannot be completed. \nYou can add logic to gracefully handle the errors. \n\nThe following is a list of possible error codes:\n\n| Name                           | Code | Description                                        |\n|--------------------------------|------|----------------------------------------------------|\n| `NETWORK_ERROR`                | 7    | There is no internet connection.                   |\n| `INVALID_DATA`                 | 8    | Invalid data is not accepted by endpoints.         |\n| `CHALLENGE_ERROR`              | 9    | JS client encountered an error on challenge setup. |\n| `INTERNAL_ERROR`               | 10   | JS client encountered an internal error.           |\n| `SESSION_TIMEOUT`              | 15   | The challenge expired.                             |\n| `TOKEN_TIMEOUT`                | 16   | The token expired.                                 |\n| `CHALLENGE_CLOSED`             | 30   | The challenge was closed by the user.              |\n| `RATE_LIMITED`                 | 31   | Spam detected.                                     |\n| `INVALID_CUSTOM_THEME`         | 32   | Invalid custom theme.                              |\n| `INSECURE_HTTP_REQUEST_ERROR`  | 33   | Insecure resource requested.                       |\n| `ERROR`                        | 29   | General failure.                                   |\n\n### Retry Failed Verification\n\nYou can indicate an automatic verification retry by setting the lambda config `HCaptchaConfig.retryPredicate`.\n\nOne must be careful to not introduce infinite retries and thus blocking the user from error recovering.\n\nExample below will automatically retry in case of `CHALLENGE_CLOSED` error:\n```java\nfinal HCaptchaConfig config = HCaptchaConfig.builder()\n        .siteKey(\"YOUR_API_SITE_KEY\")\n        .retryPredicate((config, hCaptchaException) -\u003e {\n            return hCaptchaException.getHCaptchaError() == HCaptchaError.CHALLENGE_CLOSED;\n        })\n        .build();\n...\n```\n\n### Retry predicate serialization\n\nLambda may implicitly capture variables from its surrounding context.\nFor a lambda to be serializable, all the captured variables must be serializable as well.\nFailing to meet this requirement can result in runtime errors when attempting to deserialize the lambda.\n\nThe `retryPredicate` is part of `HCaptchaConfig` that may get persist during application lifecycle.\nSo pay attention to this aspect and make sure that `retryPredicate` is serializable to avoid\n`android.os.BadParcelableException` in run-time.\n\n## Debugging Tips\n\nUseful error messages are often rendered on the hCaptcha checkbox. For example, if the sitekey within your config is invalid, you'll see a message there. To quickly debug your local instance using this tool, set `.size(HCaptchaSize.NORMAL)`\n\n`HCaptchaConfigBuilder.diagnosticLog(true)` can help to get more detailed logs.\n\n### Verify the completed challenge\n\nAfter retrieving a `token`, you should pass it to your backend in order to verify the validity of the token by doing a [server side check](https://docs.hcaptcha.com/#server) using the hCaptcha secret linked to your sitekey.\n\n---\n\n## FAQ\n\n\u003e Can I get a token in a non-UI thread?\n\nNo: the SDK depends on WebView, which is a UI component and cannot be instantiated in a non-UI thread.\n\nHowever, the SDK provides a completely silent (invisible to the end-user) mechanism with `hideDialog=true` config + \"passive\" site key (this is an Enterprise feature). But note that the token request still has to be called from the UI thread.\n\n\u003e How can I prevent the hCaptcha verification from being canceled when the back button is pressed?\n\nIt is possible by specifying `HCaptchaConfig.retryPredicate` as shown in the following code snippet:\n\n```java\nfinal HCaptchaConfig config = HCaptchaConfig.builder()\n        .siteKey(\"YOUR_API_SITE_KEY\")\n        .retryPredicate((config, hCaptchaException) -\u003e {\n            return hCaptchaException.getHCaptchaError() == HCaptchaError.CHALLENGE_CLOSED;\n        })\n        .build();\n```\n\n\u003e HCaptcha constantly failing with IllegalStateException \"Visual Challenge verification require FragmentActivity\", how to fix it?\n\nSDK expect to be initialized with `FragmentActivity` instance in regular scenario.\n\nIn case if you use passive `siteKey` make sure that you called `hideDialog(true)` on `HCaptchaCconfig.builder()`\n\n## For maintainers\n\nIf you plan to contribute to the repo, please see [MAINTAINERS.md](./MAINTAINERS.md) for detailed build, test, and release instructions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhcaptcha%2Fhcaptcha-android-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhcaptcha%2Fhcaptcha-android-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhcaptcha%2Fhcaptcha-android-sdk/lists"}