Quick draft for someone who might find this useful
Form
I am submitting my form without reloading the page so cannot use the submit event. Instead, my form has a Save button
<div id='captcha_container'></div>
<form method='post'>
<input placeholder="First Name" type="text" id="first_name" name="first_name" autocomplete="given-name">
<button id='save'>Save</button>
</form>
Scripts
1. Add to Website Script doctype
frappe.require("https://www.google.com/recaptcha/api.js")
2. Web Page Script
// add save button attributes which wouldn't work when using the page builder
// but work when using pure HTML
$(document).ready( ()=>{
$('#save').attr({
'class': 'g-recaptcha btn',
'data-sitekey':"RECAPTCHA_SITE_KEY",
'data-callback': 'onClick',
'data-action': 'click'
});
});
function onClick(token) {
// all mandatory
if(! args.first_name) {
msgprint("All fields are necessary", "Hang on buddy...");
return;
}
//verify captcha and perform your desired action
frappe.call({
"method": "my_app.api.verify_captcha",
"args": {
'token': token
},
freeze: true,
callback: (r) => {
let verified = r.message; //result is score 0.1 - 1 or false
if (verified){
if (parseFloat(verified) > 0.3){
// finally, perform your desired action
// e.g submit your form with frappe.call() or similar
}
else {
msgprint("Looks like you're a robot 🤖", "Wait a minute...");
}
}
else {
msgprint("Something's wrong with robot checker 🤖, the developers will be notified", "Uh oh...");
}
}
});
}
Python
"""file location: <frappe-bench>/apps/my_app/my_app/api.py"""
from urllib.parse import urlencode
from urllib.request import urlopen
import json
@frappe.whitelist(allow_guest=True)
def verify_captcha(token):
URL = 'https://www.google.com/recaptcha/api/siteverify'
private_key = 'RECAPTCHA_SERVER_KEY'
params = urlencode({
'secret': private_key,
'response': token,
})
data = urlopen(URL, params.encode('utf-8')).read()
result = json.loads(data)
success = result.get('success', None)
# frappe.errprint( float(result.get('score', 1)) )
if success == True:
# return the score if verification was successful
return float( result.get('score', 1) )
else:
frappe.errprint( 'reCaptcha failed ' + str(result) )
return False
Possible improvements
- Keys can be saved in a frappe doctype
- I’m running two calls to the server, first to verify the token, and a second to submit my form. One call to the server can handle both
NOTE: This is working perfectly but still not giving me data on the google analytics UI, its a known issue but I’ve given up trying
UPDATE: Report data are streaming in after a few days. The first two charts at least.