Yandex Cloud
Search
Contact UsGet started
  • Blog
  • Pricing
  • Documentation
  • All Services
  • System Status
    • Featured
    • Infrastructure & Network
    • Data Platform
    • Containers
    • Developer tools
    • Serverless
    • Security
    • Monitoring & Resources
    • ML & AI
    • Business tools
  • All Solutions
    • By industry
    • By use case
    • Economics and Pricing
    • Security
    • Technical Support
    • Customer Stories
    • Start testing with double trial credits
    • Cloud credits to scale your IT product
    • Gateway to Russia
    • Cloud for Startups
    • Education and Science
    • Yandex Cloud Partner program
  • Blog
  • Pricing
  • Documentation
© 2025 Direct Cursus Technology L.L.C.
Tutorials
    • All tutorials
    • Differentiation of access permissions for user groups
    • Creating an L7 load balancer with a Smart Web Security security profile through an Application Load Balancer Ingress controller
    • Centralized online publication and app protection against DDoS attacks
    • Delivering logs from a VM instance to Cloud Logging
    • Storing load balancer logs to PostgreSQL
    • Secure storage of GitLab CI passwords as Yandex Lockbox secrets
    • Service account with an OS Login profile for VM management via Ansible
    • Transferring logs from Container Optimized Image to Cloud Logging
    • Adding an HTML page to work with SmartCaptcha
    • Creating an L7 load balancer with a security profile
    • Alert settings in Monitoring
    • Exporting audit logs to MaxPatrol SIEM
    • Exporting audit logs to SIEM Splunk systems
    • Uploading audit logs to ArcSight SIEM
      • CAPTCHA in Android apps
      • Invisible CAPTCHA in Android apps
      • CAPTCHA in an Android app on Flutter
      • CAPTCHA in iOS apps
    • Server-side encryption for an Object Storage bucket
    • Encrypting secrets in Hashicorp Terraform
    • Managing KMS keys with Hashicorp Terraform
    • Auto Unseal in Hashicorp Vault

In this article:

  • Getting started
  • Create a CAPTCHA
  • Prepare the development tools
  • Create and run the server application
  • Create the mobile application
  • Run the application and test SmartCaptcha
  1. Security
  2. SmartCaptcha use cases
  3. CAPTCHA in an Android app on Flutter

Yandex SmartCaptcha in an Android app on Flutter

Written by
Yandex Cloud
Updated at May 7, 2025
  • Getting started
  • Create a CAPTCHA
  • Prepare the development tools
  • Create and run the server application
  • Create the mobile application
  • Run the application and test SmartCaptcha

Flutter is a Google framework for developing mobile applications. With Flutter, you can create Android and iOS apps from a single codebase. This simplifies development and allows you to release your products faster. Flutter is powered by Dart, a programming language with readily available widgets and tooling for UI development.

In this tutorial, you will learn how to create a project comprised of a server and mobile application:

  • The server application will provide an HTML page for loading SmartCaptcha and check the result of a CAPTCHA challenge solved by the mobile application user.
  • The mobile application will show a page with the CAPTCHA and send a request to check the result.

To create the project:

  1. Create a CAPTCHA.
  2. Prepare the development tools.
  3. Create and run the server application.
  4. Create the mobile application.
  5. Run the mobile application in the emulator and check SmartCaptcha operation.

Getting startedGetting started

Sign up in Yandex Cloud and create a billing account:

  1. Navigate to the management console and log in to Yandex Cloud or register a new account.
  2. On the Yandex Cloud Billing page, make sure you have a billing account linked and it has the ACTIVE or TRIAL_ACTIVE status. If you do not have a billing account, create one and link a cloud to it.

If you have an active billing account, you can navigate to the cloud page to create or select a folder for your infrastructure to operate in.

Learn more about clouds and folders.

Create a CAPTCHACreate a CAPTCHA

  1. Create a CAPTCHA.
  2. See the Overview tab to get the CAPTCHA keys:
    • Client key: To load the page with CAPTCHA.
    • Server key: To get the CAPTCHA challenge results.

Prepare the development toolsPrepare the development tools

This guide assumes that you are using your PC to complete it.

  1. Install Python.
  2. Install Flask.
  3. Install the Flutter SDK.
  4. Install Android Studio.
  5. In Android Studio, install the Dart and Flutter plugins:
    1. Go to File → Settings → Plugins.
    2. On the Marketplace tab, type Dart in the search field.
    3. Click Install to install the plugin.
    4. In the same way, find and install the Flutter plugin.
  6. Configure the path to the Flutter SDK:
    1. Go to File → Settings → Languages & Frameworks → Flutter.
    2. In the Flutter SDK path field, select the folder where you installed the Flutter SDK.

Create and run the server applicationCreate and run the server application

  1. Create a new folder, e.g., web-captcha-app.

  2. In the web-captcha-app folder, create a file named app.py:

    Server application code
    from flask import Flask, request, jsonify, render_template
    import requests
    
    app = Flask(__name__)
    
    SMARTCAPTCHA_SERVER_KEY = "<server_key>"
    
    # test endpoint
    @app.route('/', methods=['GET'])
    def helo():
        return "Hello from CAPTCHA App", 200
    
    # endpoint returning a page for embedding a CAPTCHA
    @app.route('/captcha', methods=['GET'])
    def render_captcha():
        return render_template("captcha.html")
    
    # endpoint for validating CAPTCHA challenge results
    @app.route('/validate-captcha', methods=['POST'])
    def validate_captcha():
        data = request.json
        token = data.get('token')
    
        if not token:
            return jsonify({"status": "error", "message": "Missing CAPTCHA token"}), 400
    
        # response validation
        response = requests.post(
            "https://smartcaptcha.yandexcloud.net/validate",
            data={
                "secret": SMARTCAPTCHA_SERVER_KEY,
                "token": token,
                "ip": request.remote_addr  # Optional: get user's IP
            },
            timeout=2
        )
    
        if response.status_code != 200:
            return jsonify({"status": "error", "message": "Captcha validation error"}), 500
    
        # response processing
        captcha_result = response.json()
        if captcha_result.get("status") == "ok":
            return jsonify({"status": "ok"}), 200
        else:
            return jsonify({"status": "robot"}), 200
    
    if __name__ == '__main__':
        app.run(debug=True, port=5000)
    
  3. In the web-captcha-app folder, create a folder named templates and create a captcha.html file in it:

    HTML page with a CAPTCHA code
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title>SmartCaptcha Mobile</title>
        <meta charset="UTF-8" />
        <meta
          name="viewport"
          content="width=device-width, initial-scale=1, shrink-to-fit=no"
        />
        <script>
          function onSmartCaptchaReady() {
            if (!window.smartCaptcha) {
              throw new Error("SmartCaptcha is not present");
            }
    
            const params = getParameters();
    
            const widgetId = window.smartCaptcha.render(
              "captcha-container",
              params
            );
    
            window.smartCaptcha.subscribe(
              widgetId,
              "challenge-visible",
              handleChallengeVisible
            );
    
            window.smartCaptcha.subscribe(
              widgetId,
              "challenge-hidden",
              handleChallengeHidden
            );
    
            window.smartCaptcha.subscribe(widgetId, "success", handleSuccess);
    
            if (params.invisible) {
              window.smartCaptcha.execute(widgetId);
            }
          }
    
          function handleSuccess(token) {
            // Send the CAPTCHA token to Flutter using postMessage for webview_flutter
            if (window.jsBridge) {
              window.jsBridge.postMessage(token);
            }
          }
    
          function handleChallengeVisible() {
            console.log("Challenge became visible");
          }
    
          function handleChallengeHidden() {
            console.log("Challenge hidden");
          }
    
          function getParameters() {
            const result = {};
    
            if (!window.location.search) {
              return result;
            }
    
            const queryParams = new URLSearchParams(window.location.search);
    
            queryParams.forEach((value, key) => {
              result[key] = value;
            });
    
            result.test = result.test === "true";
            result.invisible = result.invisible === "true";
            result.hideShield = result.hideShield === "true";
            result.webview = true;
    
            return result;
          }
        </script>
     
        <script>
            function reloadPage() {
              if (window.jsBridge) {
                window.jsBridge.postMessage('pageReloaded');
              }
              window.location.reload();
            }
        </script>
    
        <script
          src="https://smartcaptcha.yandexcloud.net/captcha.js?render=onload&onload=onSmartCaptchaReady"
          defer
        ></script>
      </head>
    
      <body>
        <noscript>
          You need to enable JavaScript to run this app.
        </noscript>
        <div id="captcha-container" class="smart-captcha"></div>
        <div style="margin:20px"><button onclick="reloadPage()">Reload</a>
      </body>
    </html>
    
  4. In the command line, go to the web-captcha-app folder and run the server application:

    cd web-captcha-app
    python3 app.py
    

Create the mobile applicationCreate the mobile application

  1. In Android Studio, create a new project. To do this, go to File → New → New Flutter Project.

  2. Check the path to the Flutter SDK and click Next.

  3. In the Project name field, enter a name for the project, e.g., mobile-captcha-app.

  4. Click Create.

  5. After uploading the project, replace the contents of the main.dart file with this code:

    Dart code for the mobile app
    import 'package:flutter/material.dart';
    import 'package:webview_flutter/webview_flutter.dart';
    import 'package:http/http.dart' as http;
    import 'dart:convert';
    
    void main() {
      WidgetsFlutterBinding.ensureInitialized();
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('SmartCaptcha Example'),
            ),
            body: WebViewExample(),
          ),
        );
      }
    }
    
    class WebViewExample extends StatefulWidget {
      @override
      _WebViewExampleState createState() => _WebViewExampleState();
    }
    
    class _WebViewExampleState extends State<WebViewExample> {
      late final WebViewController _controller;
      String result = "";
    
      @override
      void initState() {
        super.initState();
        _controller = WebViewController()
          ..setJavaScriptMode(JavaScriptMode.unrestricted) // enable scripting
          ..addJavaScriptChannel(                          // open a channel for application responses
            'jsBridge',
            onMessageReceived: (message) {
              if (message.message == 'pageReloaded') {
                _handlePageReload();
              } else {
                String token = message
                    .message; // getting a token from CAPTCHA
                print("CAPTCHA token received: $token");
                _sendTokenToServer(token); // sending a token for validation
              }
            },
          );
        _loadCaptchaPageFromServer();
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            Expanded(child: WebViewWidget(controller: _controller)),
            SizedBox(height: 20),
            if (result.isNotEmpty)
              Text(
                result,
                style: TextStyle(fontSize: 20, color: result == "Passed" ? Colors.green : Colors.red),
              ),
          ],
        );
      }
    
      void _loadCaptchaPageFromServer() {
        setState(() {
          result = "Not Done";  // resetting status on initial page load
        });
        // uploading CAPTCHA
        _controller.loadRequest(Uri.parse('<server_application_URL>:5000/captcha?sitekey=<client_key>'));  
        // replace the placeholder with the obtained client key
      }
    
      void _handlePageReload() {
        setState(() {
          result = "Not Done"; // Resetting status on page reload
        });
      }
    
      Future<void> _sendTokenToServer(String token) async {
        const String serverValidationUrl = '<server_application_URL>:5000/validate-captcha';  
        // replace the placeholder with the obtained client key
    
        try {
          setState(() {
            result = "Checking"; // Setting token validation status
          });
    
          final response = await http.post(
            Uri.parse(serverValidationUrl),
            body: jsonEncode({'token': token}),
            headers: {
              'Content-Type': 'application/json',
            },
          );
    
          if (response.statusCode == 200) {
            var jsonResponse = jsonDecode(response.body);
            setState(() {
              result = jsonResponse['status'] == 'ok' ? 'Passed' : 'Robot';
            });
          } else {
            setState(() {
              result = 'Error';
            });
          }
        } catch (e) {
          print('Error: $e');
          setState(() {
            result = 'Error';
          });
        }
      }
    }
    

    Warning

    If you are running the server application on a computer with Flutter and Android Studio, do not use http://localhost as the server URL. Use an internal subnet IP address, e.g., http://10.0.2.2.

  6. Add the required dependencies:

    1. Open the pubspec.yaml file in the project root.
    2. In the dependencies section, add webview_flutter and http:
    dependencies:
    flutter:
        sdk: flutter
    
        # add webview_flutter and http
        webview_flutter: ^4.0.0
        http: ^0.13.5
    
  7. To use HTTP for testing, do the following:

    1. Open the \android\app\src\main\AndroidManifest.xml file.
    2. Add android:usesCleartextTraffic="true" to the application section:
    <application
    android:label="capcha_app"
    android:name="${applicationName}"
    android:icon="@mipmap/ic_launcher"
    <!-- Add this row -->
    android:usesCleartextTraffic="true"
    >
    

Run the application and test SmartCaptchaRun the application and test SmartCaptcha

To run your mobile app on the emulator:

  1. In Android Studio, go to Tools → Device Manager and activate the mobile device, e.g., the pre-installed default Medium Phone API 35.
  2. Run the main.dart file in one of the following ways:
    • In the top panel next to the file name, click the start button.
    • Go to Run → Run 'main.dart'.
  3. Wait for the compilation to complete and the application to load into the emulator.

To test SmartCaptcha:

  1. Solve the CAPTCHA challenge.
  2. If you solved the challenge correctly, the red Not Done status at the bottom of the application screen will briefly change to Checking and then to the green Passed status.
  3. To repeat the test, click Reload on the page below the CAPTCHA.

Was the article helpful?

Previous
Invisible CAPTCHA in Android apps
Next
CAPTCHA in iOS apps
© 2025 Direct Cursus Technology L.L.C.