Integrate Captcha V3 into a Flutter application
Use the mobile HTML5 version of Alibaba Cloud Captcha 2.0 in your Flutter hybrid app by loading it inside a WebView component. This approach avoids native SDK dependency conflicts and lets you apply Captcha updates without rebuilding the app.
How it works
The integration connects three components:
HTML5 page (client side): The HTML5 business page loads Captcha 2.0, presents the verification challenge, and passes the resulting
captchaVerifyParamtoken to Flutter through a JavaScript channel.Application server (server side): Your server receives the token from Flutter and calls the
VerifyIntelligentCaptchaAPI operation to confirm the result is genuine.Flutter app: A WebView component loads the HTML5 business page. A JavaScript channel bridges the HTML5 page and your Dart code, so verification tokens flow directly into Flutter.
Server-side verification is mandatory. Without it, the client-side token can be forged and the CAPTCHA provides no protection.
Prerequisites
Before you begin, ensure that you have:
Created a verification scenario with Integration Method set to Webview+H5 (for Apps And WeChat Mini Programs)
Flutter 2.0 or later
The
webview_flutterplugin installed
Step 1: Integrate Captcha 2.0 on the HTML5 client side
Follow Integrate with Captcha using the V3 architecture for web and HTML5 clients to add Captcha 2.0 to your HTML5 business page.
If your service uses the V2 architecture, see Integrate with Captcha using the V2 architecture for web and HTML5 clients instead.
In the Captcha success callback, post captchaVerifyParam to the Flutter JavaScript channel named testInterface:
// Success callback — called after the user passes the CAPTCHA challenge
function success(captchaVerifyParam) {
console.log(captchaVerifyParam);
// Send the verification token to Flutter via the JavaScript channel.
if (window.testInterface) {
window.testInterface.postMessage(captchaVerifyParam);
}
}Step 2: Integrate Captcha 2.0 on the server side
On your application server, integrate the server-side software development kit (SDK) for Captcha 2.0 and call the VerifyIntelligentCaptcha API operation to perform secondary authentication. For details, see Server-side integration.
Always perform server-side verification before granting access. Skipping this step allows attackers to forge CAPTCHA tokens and bypass human verification entirely.
Step 3: Set up the Flutter app
Add the webview_flutter dependency
In pubspec.yaml, add webview_flutter under dependencies:
dependencies:
flutter:
sdk: flutter
webview_flutter: ^4.13.0 # Use the latest versionInstall the dependency:
flutter pub getConfigure Android network permissions
Add the following permissions to android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<application
...
android:usesCleartextTraffic="true"
...
>Create the Captcha WebView page
Create captcha_page.dart. The key configuration points are:
JavaScriptMode.unrestricted— required for Captcha 2.0 scripts to execute.addJavaScriptChannel('testInterface', ...)— receivescaptchaVerifyParamfrom the HTML5 success callback.loadHtmlString(htmlContent, baseUrl: 'https://your-domain.com')— loads the local HTML5 page with a trusted origin.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import 'package:flutter/services.dart';
class CaptchaPage extends StatefulWidget {
const CaptchaPage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<CaptchaPage> createState() => _CaptchaPageState();
}
class _CaptchaPageState extends State<CaptchaPage> {
WebViewController? _controller;
String _verifyResult = "Waiting for verification";
bool _isLoading = true;
@override
void initState() {
super.initState();
_initWebView();
}
Future<void> _initWebView() async {
// Load the local HTML file.
String htmlContent = await rootBundle.loadString('assets/index.html');
// Configure the WebView controller.
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
// Add a JavaScript channel to receive captchaVerifyParam from the HTML5 page.
..addJavaScriptChannel('testInterface', onMessageReceived: (JavaScriptMessage message) {
// Print the complete verification parameters to the console.
print('Received Captcha parameters: ${message.message}');
// Forward captchaVerifyParam to your server for secondary authentication.
setState(() {
_verifyResult = "Verified";
});
})
..setNavigationDelegate(
NavigationDelegate(
onPageFinished: (url) {
setState(() {
_isLoading = false;
});
},
),
)
// Load the local HTML file. You can also load an HTML5 URL.
..loadHtmlString(htmlContent, baseUrl: 'https://your-domain.com');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _controller == null
? const Center(child: CircularProgressIndicator())
: Column(
children: [
Expanded(
child: Stack(
children: [
WebViewWidget(controller: _controller!),
if (_isLoading)
const Center(
child: CircularProgressIndicator(),
),
],
),
),
Container(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Text('Verification status: $_verifyResult', style: const TextStyle(fontSize: 16)),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
if (_controller != null) {
_controller!.runJavaScript('initCaptcha()');
setState(() {
_verifyResult = "Captcha reset";
});
}
},
child: const Text('Reset Captcha'),
),
],
),
),
],
),
);
}
}Use the Captcha page in main.dart
import 'package:flutter/material.dart';
import 'captcha_page.dart'; // Import the Captcha page.
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Alibaba Cloud Captcha Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const CaptchaPage(title: 'Alibaba Cloud Captcha Demo'),
);
}
}Register the HTML5 asset
In pubspec.yaml, add the HTML5 file path under flutter:
flutter:
assets:
- assets/index.htmlVerify the integration
Run your Flutter app and trigger the CAPTCHA challenge. If the verification completes and your app receives the captchaVerifyParam token, the client-side integration is working. Confirm that your server successfully calls VerifyIntelligentCaptcha and returns the expected result.
Troubleshooting
The CAPTCHA widget does not load
JavaScript must be enabled. Confirm that setJavaScriptMode(JavaScriptMode.unrestricted) is set on the WebViewController. Without it, Captcha 2.0 scripts cannot execute.
The JavaScript channel receives no message
The channel name in your HTML5 success callback (window.testInterface) must exactly match the name passed to addJavaScriptChannel in Dart ('testInterface'). A mismatch silently drops messages.
The page loads but CAPTCHA challenges fail
Confirm that Android network permissions are set in AndroidManifest.xml (INTERNET, ACCESS_NETWORK_STATE, ACCESS_WIFI_STATE) and that android:usesCleartextTraffic="true" is present if your HTML5 page or Captcha endpoint uses HTTP.
Download the demo
What's next
Server-side integration — complete the secondary authentication flow on your server.
Integrate with Captcha using the V3 architecture for web and HTML5 clients — details on the HTML5 client-side integration referenced in Step 1.