flutter_recaptcha

A professional, fully themeable Flutter CAPTCHA widget. It generates a distorted, noisy challenge image and validates it against user input — entirely on-device, with no external service, API key, or network access required.

Features

  • 8 built-in designs via CaptchaStyleTypeclassic, modern, minimalist, dark, neon, playful, ocean, sunset — or supply a fully custom CaptchaThemeData for complete control.
  • Selectable character sets via CaptchaCharacterTypenumbersOnly, lettersOnly, or alphanumeric — with configurable length and automatic exclusion of visually confusable characters (0/O, 1/l/I) by default.
  • Custom rendering — a CustomPainter draws randomly rotated, distorted CAPTCHA text over a themed noisy background.
  • Built-in validation — combines the CAPTCHA display with a text field and reports success/failure through onVerified.
  • Automatic reset — the input field is cleared and a fresh challenge is generated after a failed attempt or a manual refresh (clearFieldOnRegenerate / autoRegenerateOnFailure).
  • Programmatic control — drive the widget from outside via a GlobalKey<CaptchaWidgetState>: call regenerate() or verify() from anywhere in your UI.
  • No dependencies beyond the Flutter SDK, and no network access.

Getting started

Add the package to your pubspec.yaml:

dependencies:
  flutter_recaptcha: ^0.1.0

Then import it:

import 'package:flutter_recaptcha/flutter_recaptcha.dart';

Usage

Basic

CaptchaWidget(
  onVerified: (isValid) {
    if (isValid) {
      // proceed
    }
  },
)

Choosing a design

CaptchaWidget(
  style: CaptchaStyleType.dark, // classic · modern · minimalist · dark ·
                                 // neon · playful · ocean · sunset
  onVerified: (isValid) => handle(isValid),
)

Choosing a character set

CaptchaWidget(
  characterType: CaptchaCharacterType.numbersOnly, // or lettersOnly / alphanumeric
  length: 5,
  onVerified: (isValid) => handle(isValid),
)

Full custom theme

CaptchaWidget(
  theme: CaptchaThemeData.modern().copyWith(
    backgroundColor: Colors.deepPurple.shade50,
    verifyButtonColor: Colors.deepPurple,
    borderRadius: 24,
  ),
)

Driving it from outside the widget

final captchaKey = GlobalKey<CaptchaWidgetState>();

CaptchaWidget(key: captchaKey, controller: myController)

// Elsewhere, e.g. after an unrelated form error:
captchaKey.currentState?.regenerate();
captchaKey.currentState?.verify();

Providing your own controller

final controller = TextEditingController();

CaptchaWidget(
  controller: controller,
  onVerified: (isValid) => handle(isValid),
)

The controller is cleared automatically whenever a new challenge is generated (see clearFieldOnRegenerate), so you don't need to clear it yourself after a failed attempt or refresh.

See the example folder for a complete, runnable app that lets you switch between every style and character type live.

API overview

Type Purpose
CaptchaWidget The main widget: canvas, input field, and verify/refresh controls.
CaptchaWidgetState Public state exposing regenerate() and verify().
CaptchaStyleType Enum of built-in visual designs.
CaptchaThemeData Immutable theme object (colors, noise, rotation, shadows, glow); one factory per style, plus copyWith.
CaptchaCharacterType Enum selecting digits / letters / both, with a generate() helper.
CaptchaPainter The CustomPainter used internally to draw the challenge.

Additional information

Found a bug or want a feature? Open an issue or pull request on the GitHub repository.

Libraries

flutter_recaptcha