How to use ReCaptcha in Flutter web

1,684

Solution 1

You can try g_recaptcha_v3 package

Note:

  • it support reCAPTCHA V3 only and not V2
  • its for Flutter Web only

Solution 2

I found this solution for reCaptcha v2:

Create a folder called html in the root folder of your project and in that folder create the file recaptcha.html.

<html>
  <head>
    <title>reCAPTCHA</title>
    <script src="https://www.google.com/recaptcha/api.js" async defer> 
</script>
  </head>
  <body style='background-color: aqua;'>
    <div style='height: 60px;'></div>
    <form action="?" method="POST">
      <div class="g-recaptcha" 
        data-sitekey="xxxxxxxxxxxxxxxxxxxxxxx"
        data-callback="captchaCallback"></div>

    </form>
    <script>
      function captchaCallback(response){
        //console.log(response);
        alert(response);
        if(typeof Captcha!=="undefined"){
          Captcha.postMessage(response);
        }
      }
    </script>
  </body>
</html>

Then add the new folder html on your pubspec.yaml file under assets

  assets:
    - fonts/
    - html/

Finally, change the initState() of your _TestPluginState to:

    ui.platformViewRegistry.registerViewFactory(
      createdViewId,
      (int viewId) => html.IFrameElement()
        ..style.height = '100%'
        ..style.width = '100%'
        ..src = '/assets/html/recaptcha.html'
        ..style.border = 'none',
    );

IMPORTANT: Do not forget to change ..srcdoc to ..src

Share:
1,684
Landon Stahl
Author by

Landon Stahl

Updated on December 28, 2022

Comments

  • Landon Stahl
    Landon Stahl over 1 year

    I need to set up a captcha for my Flutter web app, but all the packages that currently exist for captcha in Flutter do not support web. To solve this issue I first tried to render the ReCaptcha box inside dart using an IFrameElement and an HTMLElementView, but the issue I get there is that when I push the code onto my domain, it says that I have given an invalid domain for the site key.

    enter image description here

    I can't understand why the site key would be invalid, I have checked and double checked the site key to make sure it matches the one for the domain I put in the ReCaptcha console. Is it possible that the IFrame is not allowing communication to the ReCaptcha API? Here is the code for that.

    import 'package:flutter/material.dart';
    import 'dart:ui' as ui;
    import 'dart:html' as html;
    import 'dart:js' as js;
    
    class platformViewRegistry {
      static registerViewFactory(String viewId, dynamic cb) {
        // ignore:undefined_prefixed_name
        ui.platformViewRegistry.registerViewFactory(viewId, cb);
      }
    }
    
    class TestPlugin extends StatefulWidget {
      TestPlugin();
    
      _TestPluginState createState() => _TestPluginState();
    }
    
    class _TestPluginState extends State<TestPlugin> {
      String createdViewId = 'map_element';
    
      @override
      void initState() {
        // ignore: undefined_prefixed_name
        ui.platformViewRegistry.registerViewFactory(
            createdViewId,
            (int viewId) => html.IFrameElement()
              ..width = MediaQuery.of(context).size.width.toString()
              ..height = MediaQuery.of(context).size.height.toString()
              ..srcdoc = """<!DOCTYPE html><html>
      <head>
        <title>reCAPTCHA</title>
        <script src="https://www.google.com/recaptcha/api.js" async defer></script>
      </head>
      <body style='background-color: aqua;'>
        <div style='height: 60px;'></div>
        <form action="?" method="POST">
          <div class="g-recaptcha" 
            data-sitekey="mySitekey"
            data-callback="captchaCallback"></div>
    
        </form>
        <script>
          function captchaCallback(response){
            //console.log(response);
            alert(response);
            if(typeof Captcha!=="undefined"){
              Captcha.postMessage(response);
            }
          }
        </script>
      </body>
    </html>"""
              ..style.border = 'none');
    
        super.initState();
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.symmetric(horizontal: 10),
          decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(color: Colors.grey[300], width: 1),
              borderRadius: BorderRadius.all(Radius.circular(5))),
          width: 200,
          height: 200,
          child: Directionality(
            textDirection: TextDirection.ltr,
            child: HtmlElementView(
              viewType: createdViewId,
            ),
          ),
        );
      }
    }
    

    Is it possible to set up a separate HTML site on a different domain, and have Flutter web display and interface through that site to fill out the captcha? Would the captcha still work if it were through an interface like that?

    Thank you in advance for your help.