58

I'm using Google reCAPTCHA and have been able to add the CAPTCHA component to my page inside a form. But when I submit the form there's no validation taking place to check if the CAPTCHA has been solved.

How do I validate that the CAPTCHA component has been solved when submitting my form? Or, in other words, how do I make my CAPTCHA component required?

Kameron
  • 10,240
  • 4
  • 13
  • 26
Baikare Sandip
  • 751
  • 1
  • 6
  • 19

8 Answers8

98

if you want to use the native html5 popups, than here is the solution

JavaScript:

window.addEventListener('load', () => {
  const $recaptcha = document.querySelector('#g-recaptcha-response');
  if ($recaptcha) {
    $recaptcha.setAttribute('required', 'required');
  }
})

CSS:

#g-recaptcha-response {
  display: block !important;
  position: absolute;
  margin: -78px 0 0 0 !important;
  width: 302px !important;
  height: 76px !important;
  z-index: -999999;
  opacity: 0;
}
Fred
  • 868
  • 10
  • 22
  • 1
    I like this approach but get an error "An invalid form control with name='g-recaptcha-response' is not focusable." – timkado Aug 17 '18 at 13:52
  • @timkado Do you have a Codepen for me? – Fred Aug 19 '18 at 13:03
  • @timkado works like expected: https://codepen.io/internetztube/pen/aaoLqM – Fred Aug 19 '18 at 13:12
  • 1
    Hi Fred - this is very strange. I copied your code and I am still getting the same error: An invalid form control with name='g-recaptcha-response' is not focusable. – timkado Aug 20 '18 at 15:34
  • @timkado What browser on what os do you use? – Fred Aug 20 '18 at 15:49
  • I am on Win8, latest version Chrome – timkado Aug 20 '18 at 15:56
  • This answer worked for me on Chrome, FF, Edge and Opera. Why isn't it working on IE 11? Any specific reason? The required attribute isn't being added to the #g-recaptcha-response id. Why? – Fernando Jun 04 '20 at 19:32
  • @Fernando Do you have a Codepen for me? – Fred Jun 08 '20 at 11:13
  • 4
    It worked well for me. There happened the same error @timkado met but was removed after adding the given CSS style. It's because the target Textarea has "display: none;" by default. Thanks, @Fred! – iconique Oct 03 '20 at 06:03
  • 3
    So close, but if the captcha expires, this doesn't catch it. – Robert McKee Feb 09 '21 at 02:13
21

I had the same problem as yours and solved it this way:

First declare a variable that stores 1 or 0 depending or whether the user filled the capcha correctly.

var allowSubmit = false;

Then you need a function which gets executed when the user fills the reCapcha correctly:

function capcha_filled () {
    allowSubmit = true;
}

... and a function that gets executed when the reCapcha session expires:

function capcha_expired () {
    allowSubmit = false;
}

To tell reCapcha about your functions (callbacks), set those data-attributes in your html:

<div class="g-recaptcha"
   data-callback="capcha_filled"
   data-expired-callback="capcha_expired"
   data-sitekey="your site key"></div>

Or if you use explicit load:

  var onloadCallback = function() {
    grecaptcha.render('your_div_id', {
      'sitekey' : 'your_site_key',
      'callback': capcha_filled,
      'expired-callback': capcha_expired,
    });
  };

You need also a callback for the form submission:

function check_if_capcha_is_filled (e) {
    if(allowSubmit) return true;
    e.preventDefault();
    alert('Fill in the capcha!');
}

Finally add in the form the onsubmit attribute:

<form action="..." onsubmit="check_if_capcha_is_filled">

Note: as mentioned in the comments, a server validation is still needed. The code prevents accidentally submitting the form unless the capcha is filled and is only for user's convenience.

Al.G.
  • 4,327
  • 6
  • 31
  • 56
  • What's to stop me from entering a javascript console and just setting `submit = true` myself? – Ian MacDonald May 19 '16 at 13:11
  • 1
    @IanMacDonald Absolutely nothing. It's (my answer) just for user's convenience. The idea is to prevent them from accidentally submitting the form (e.g. pressing enter on an ) without having filled the capcha. Just saving a page reload for better user experience. – Al.G. May 19 '16 at 18:54
  • Oh, I got your point now. I should have explicitly mentioned that a server check is still required. Thanks for the note. – Al.G. May 19 '16 at 18:55
17

I found this to be a quick & easy way to do it. Add this to your headers:

<script>
window.onload = function() {
  var recaptcha = document.forms["myForm"]["g-recaptcha-response"];
  recaptcha.required = true;
  recaptcha.oninvalid = function(e) {
    // do something
    alert("Please complete the captcha");
  }
}
</script>

This only works in HTML5, and is (or should be) supported by these browsers: http://caniuse.com/#feat=form-validation

(The JS console in Chrome shows this error message: "Invalid form control" only in Google Chrome , and I haven't been able to work around this. Hopefully someone else will improve this response.)

Community
  • 1
  • 1
secenv
  • 191
  • 1
  • 6
  • This works when you test manually. But will this work if the form will be submitted by a bot? :D It might not. – Larstton Aug 05 '23 at 13:12
11

I checked for existance of #g-recaptcha-response:

function checkRecaptcha() {
    res = $('#g-recaptcha-response').val();

    if (res == "" || res == undefined || res.length == 0)
        return false;
    else
        return true;
}

//...

$('#frm-signup').submit(function(e) {

    if(!checkRecaptcha()) {
        $( "#frm-result" ).text("Please validate your reCAPTCHA.");
        return false;
    }
    //...
});

This really should be part of the docs...

citynorman
  • 4,918
  • 3
  • 38
  • 39
5

Working solution in 2022

Personally, I was not able to get any of the above solutions to work with my captcha. So I figured I would share my current working solution for those facing the same issue.

The accepted answer doesn't have a validation technique for when the captcha expires, the below solution addresses that.

My notes in the .js should explain the solution thoroughly.

JavaScript

// By default do not allow form submission.
var allow_submit = false

function captcha_filled () {
    /*
     * This is called when Google get's the recaptcha response and approves it.
     * Setting allow_submit = true will let the form POST as normal.
     * */

    allow_submit = true
}

function captcha_expired () {
    /*
     * This is called when Google determines too much time has passed and expires the approval.
     * Setting allow_submit = false will prevent the form from being submitted.
     * */

    allow_submit = false
}


function check_captcha_filled (e) {
    console.log('captcha-verified')
    /*
     * This will be called when the form is submitted.
     * If Google determines the captcha is OK, it will have
     * called captcha_filled which sets allow_submit = true
     * If the captcha has not been filled out, allow_submit
     * will still be false.
     * We check allow_submit and prevent the form from being submitted
     * if the value of allow_submit is false.
     * */

    // If captcha_filled has not been called, allow_submit will be false.
    // In this case, we want to prevent the form from being submitted.
    if (!allow_submit) {
        // This call prevents the form submission.
        // e.preventDefault()

        // This alert is temporary - you should replace it with whatever you want
        // to do if the captcha has not been filled out.
        alert('ERROR: Please verify you are human by filling out the captcha')

        return false
    }
    captcha_expired()
    return true
}

HTML

<form action="post" onsubmit="return check_captcha_filled()">
<!-- form items -->
<div class="g-recaptcha"
   data-callback="captcha_filled"
   data-expired-callback="captcha_expired"
   data-sitekey="your site key">
</div>
</form>
Kameron
  • 10,240
  • 4
  • 13
  • 26
2

If you want a more friendly and descriptive message, you can add a required checkbox. This will ensure the html5 popup shows something like: "Please check this box if you want to proceed"

<div class="captcha">
   <div class="g-recaptcha" data-sitekey="Your Site Key" data-callback="removeFakeCaptcha"></div>
   <input type="checkbox" class="captcha-fake-field" tabindex="-1" required>
</div>

Add the code to remove the fake captcha once completed

window.removeFakeCaptcha = function() {
   document.querySelector('.captcha-fake-field').remove();
}

Then on the css you hide the checkbox and position it to the captcha box:

.captcha {
  position: relative;
}
.captcha-fake-field {
  background: transparent;
  bottom: 0;
  border: none;
  display: block;
  height: 1px;
  left: 12px;
  width: 1px;
  position: absolute;
  z-index: -1;
}
Cacobala
  • 31
  • 2
0

Not sure if you already solved this, but you could use an addon to validate the Google recaptcha: http://formvalidation.io/addons/recaptcha2/

ForTheWin
  • 617
  • 1
  • 8
  • 15
0

I find this very helpful:

<div class="g-recaptcha myPopover" data-sitekey="Your Key" 
        data-callback="recaptchaCallback">

You add a function to data-callback="recaptchaCallback" with this code:

var recaptchachecked=false; 
function recaptchaCallback() {
    recaptchachecked = true;
}

and a function were you return the value to use it in a other html-tag like this:

<form method="post" onsubmit="return isreCaptchaChecked()">
function isreCaptchaChecked()
{
    return recaptchachecked;
}

I hope this helps you.