friendly_captcha_flutter

pub package pub points License: MIT

FriendlyCaptcha v2 widget for Flutter. Privacy-first, accessible, proof-of-work bot protection on Android, iOS, and Web (Wasm-compatible).

The package only renders the captcha and surfaces the solution token. Verification stays on your backend.

Install

flutter pub add friendly_captcha_flutter

Web setup

Add the FriendlyCaptcha SDK to web/index.html, ideally in <head> so it loads before Flutter boots:

<script type="module" src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk@1/site.min.js" async defer></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk@1/site.compat.min.js" async defer></script>

If you ship a strict Content-Security-Policy, allow script-src cdn.jsdelivr.net (or self-host the SDK and allow your own origin), connect-src https://api.friendlycaptcha.com (or https://eu-api.friendlycaptcha.com for FriendlyCaptchaApiEndpoint.eu), and worker-src 'self' blob: — the SDK uses a worker for the proof-of-work loop.

Mobile setup

Sitekeys are origin-bound and the SDK rejects data: / about:blank, so the embedded WebView serves its HTML under a synthetic origin (defaults to https://app.local). Either:

  • Add app.local to your sitekey's allowed-hostnames list in the FriendlyCaptcha dashboard, or
  • Override the origin once at app startup to match a hostname you already allow:
void main() {
  FriendlyCaptcha.mobileOrigin = 'https://signup.yourdomain.com';
  runApp(const MyApp());
}

No further Android/iOS setup is required — flutter_inappwebview handles the platform plumbing.

Basic usage

FriendlyCaptcha(
  sitekey: 'FCMG...',
  onResult: (result) {
    if (result.isCompleted) {
      submitToYourBackend(result.solution!);
    }
  },
)

onResult fires only on terminal events (completed, error, expired). Use the controller below if you need intermediate states.

Controller usage

final captcha = FriendlyCaptchaController();

@override
Widget build(BuildContext context) {
  return Column(
    children: [
      FriendlyCaptcha(
        sitekey: 'FCMG...',
        controller: captcha,
        onResult: (_) {},
      ),
      ListenableBuilder(
        listenable: captcha,
        builder: (_, __) => FilledButton(
          onPressed: captcha.hasSolution
              ? () => _submit(captcha.solution!).then((ok) {
                    if (!ok) captcha.reset();
                  })
              : null,
          child: const Text('Submit'),
        ),
      ),
    ],
  );
}

Solutions are single-use and expire after roughly 10 minutes, so call controller.reset() after a failed submission to arm a fresh challenge.

Configuration

Parameter Type Default Notes
sitekey String required Sitekey from the FriendlyCaptcha dashboard.
onResult ValueChanged<…Result> required Fires only on completed / error / expired.
controller FriendlyCaptchaController? null Drive start() / reset() and observe statechanges.
theme FriendlyCaptchaTheme auto light, dark, or auto.
startMode FriendlyCaptchaStartMode focus auto, focus, or none.
apiEndpoint FriendlyCaptchaApiEndpoint global global or eu for data-residency.
language String? null (auto) Force a UI language (e.g. de, fr).
height double 80 Pixel height of the embed.

Plus the static FriendlyCaptcha.mobileOrigin (default https://app.local) covered above.

Server-side verification

This package is intentionally client-side only. After a solution token arrives via onResult, POST it to your own server and call POST https://api.friendlycaptcha.com/api/v2/captcha/siteverify with your secret API key — see the FriendlyCaptcha docs for the request format. The package deliberately ships no helper for this so secret keys never live in your app bundle.

Testing

For widget-level tests or end-to-end CI runs, use one of FriendlyCaptcha's automated-testing sitekeys (e.g. the always-pass key documented there) so you don't burn real captcha solves.

Platform support

Platform Status
Android Supported via flutter_inappwebview.
iOS Supported via flutter_inappwebview.
Web Supported via dart:js_interop + package:web. Compiles under dart2wasm.
Desktop Not supported.

License

MIT — see LICENSE.

Libraries

friendly_captcha_flutter
FriendlyCaptcha v2 widget for Flutter. See https://developer.friendlycaptcha.com/docs/v2/ for the upstream SDK and README.md for setup instructions.