Flutter SDK
Add Crovly captcha to Flutter apps. WebView widget with Dart callbacks, works on Android and iOS.
Installation
Add to your pubspec.yaml:
dependencies:
crovly_flutter: ^1.0.0Then run:
flutter pub getGet your site key at app.crovly.com.
Basic Usage
import 'package:crovly_flutter/crovly_flutter.dart';
class LoginPage extends StatefulWidget {
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
String? _token;
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(decoration: InputDecoration(labelText: 'Email')),
TextField(decoration: InputDecoration(labelText: 'Password'), obscureText: true),
SizedBox(height: 16),
CrovlyCaptcha(
siteKey: 'YOUR_SITE_KEY',
onVerify: (token) => setState(() => _token = token),
onError: (code, message) => print('Error: $code - $message'),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: _token != null ? _handleSubmit : null,
child: Text('Sign In'),
),
],
);
}
Future<void> _handleSubmit() async {
// Send _token to your backend for verification
}
}Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
siteKey | String | — | Your public site key (required) |
theme | CrovlyTheme | .auto | Widget theme |
size | CrovlySize | .normal | Widget size mode |
lang | String? | Auto-detect | Language code (e.g. 'tr', 'ar') |
onVerify | void Function(String) | — | Called on successful verification |
onError | void Function(String, String) | — | Called on error |
onExpire | VoidCallback | — | Called when token expires |
apiUrl | String | https://get.crovly.com | Widget script CDN |
width | double | double.infinity | Widget width |
height | double | 65 | Widget height |
decoration | BoxDecoration? | — | Container decoration |
Theme Options
CrovlyCaptcha(
siteKey: 'YOUR_SITE_KEY',
theme: CrovlyTheme.dark, // .light, .dark, or .auto
onVerify: (token) => setState(() => _token = token),
)Form Example
class ContactForm extends StatefulWidget {
@override
State<ContactForm> createState() => _ContactFormState();
}
class _ContactFormState extends State<ContactForm> {
final _formKey = GlobalKey<FormState>();
String? _token;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Name'),
validator: (v) => v?.isEmpty == true ? 'Required' : null,
),
TextFormField(
decoration: InputDecoration(labelText: 'Message'),
maxLines: 4,
validator: (v) => v?.isEmpty == true ? 'Required' : null,
),
SizedBox(height: 16),
CrovlyCaptcha(
siteKey: 'YOUR_SITE_KEY',
theme: CrovlyTheme.auto,
onVerify: (token) => setState(() => _token = token),
onExpire: () => setState(() => _token = null),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: _token != null && _formKey.currentState!.validate()
? _submit
: null,
child: Text('Send'),
),
],
),
);
}
Future<void> _submit() async {
final response = await http.post(
Uri.parse('https://your-api.com/contact'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'token': _token}),
);
// Handle response
}
}Custom Styling
CrovlyCaptcha(
siteKey: 'YOUR_SITE_KEY',
width: 320,
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.grey.shade300),
),
onVerify: (token) => setState(() => _token = token),
)Backend Verification
After getting the token, verify it on your server using any of the server-side SDKs:
// Using the Python SDK on your backend
from crovly import Crovly
client = Crovly("crvl_secret_YOUR_SECRET_KEY")
result = client.verify(token, expected_ip=request.remote_addr)
if not result.success:
return {"error": "Captcha failed"}, 403Platform Requirements
- Android: minSdkVersion 19+
- iOS: iOS 12.0+
- Flutter: 3.10.0+
- Dart: 3.0.0+