Skip to main content

Trying to implement reCAPTCHA on a force.com site. Has anyone done this? 

There is a way to implement ReCaptcha on a Skuid page using a Field Editor, some JS, and a template below the field editor. There are a few tricks that need to be updated for it to work properly:


  1. When someone updates any field that has a popup, such as date fields or reference fields, the ReCaptcha piece goes away. It needs to be reset using JS

  2. We need to know when the user successfully validates ReCaptcha, so the save button can be enabled

Here’s how it can be implemented.



  1. Put a template below the Field Editor that contains the following:




    1. Have an inline Javascript snippet that contains the following:


      var captchaCallback = function(data) {

      var model = skuid.model.getModel(“CaptchaValidated”);

      model.updateRow(model.getFirstRow(), {isValid:true});

      }

      var onloadCallback = function() {

      grecaptcha.render(‘recaptchaElement’, {

      ‘sitekey’ : ‘syour-site-key]’,

      ‘callback’: captchaCallback

      });

      };



    Make sure to replace >your-site-code] with your own ReCaptcha site key. The first method is called when the user successfully validates, and it sets a field “isValid” in a UI-only model to true. I put a save button in a button set and in the rendering tab, made the button disabled until this flag is true:



    1. Add a template to the Field Editor to display the ReCaptcha component. The template should contain:




    2. Have another JS Snippet that you can call when a row is updated. The snippet should have the following code:


      var params = arguments 0],

      $ = skuid.$;


      onloadCallback();




    3. When any row is updated in your model, call this snippet:



    The page I did looks like this:




For reference, here’s the XML of the page I used to demonstrate ReCaptcha:


<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" useviewportmeta="true" showheader="true">
<models>
<model id="NewTask" limit="1" query="false" createrowifnonefound="true" datasource="salesforce" sobject="Task">
<fields>
<field id="AccountId"/>
<field id="Account.Name"/>
<field id="CallType"/>
<field id="ActivityDate"/>
<field id="WhatId"/>
<field id="What.Name"/>
</fields>
<conditions/>
<actions>
<action>
<actions>
<action type="custom" snippet="recaptchaRefresh"/>
</actions>
<events>
<event>row.updated</event>
</events>
</action>
</actions>
</model>
<model id="CaptchaValidated" query="true" createrowifnonefound="true" datasource="Ui-Only" processonclient="true">
<fields>
<field id="isValid" displaytype="BOOLEAN" ogdisplaytype="TEXT"/>
</fields>
<conditions/>
<actions/>
</model>
</models>
<components>
<buttonset model="CaptchaValidated" uniqueid="sk-Wht-1313">
<buttons>
<button type="multi" label="Save" uniqueid="sk-Wht-1318" icon="fa-check" window="self">
<renderconditions logictype="and"/>
<enableconditions logictype="and">
<condition type="fieldvalue" operator="=" enclosevalueinquotes="false" fieldmodel="CaptchaValidated" sourcetype="fieldvalue" field="isValid" value="true"/>
</enableconditions>
<actions>
<action type="save">
<models>
<model>NewTask</model>
<model>CaptchaValidated</model>
</models>
</action>
</actions>
</button>
<button type="cancel" label="Cancel" uniqueid="sk-Wht-1322" window="self">
<models>
<model>NewTask</model>
</models>
<hotkeys/>
<renderconditions logictype="and"/>
<enableconditions/>
</button>
</buttons>
</buttonset>
<basicfieldeditor showheader="true" showsavecancel="false" showerrorsinline="true" model="NewTask" uniqueid="sk-Wht-253" mode="edit">
<columns>
<column width="50%">
<sections>
<section title="Section A" collapsible="no" showheader="false">
<fields>
<field uniqueid="sk-Wht-290" id="AccountId"/>
<field uniqueid="sk-Wht-291" id="CallType"/>
<field uniqueid="sk-Wht-292" id="ActivityDate"/>
<field uniqueid="sk-Wht-293" id="WhatId"/>
</fields>
</section>
</sections>
</column>
<column width="50%">
<sections>
<section title="Section B" collapsible="no" showheader="false">
<fields>
<field uniqueid="sk-Wht-306" type="COMBO" editmodebehavior="autopopup" readonly="true">
<label>Re-Captcha</label>
<renderconditions logictype="and" onhidedatabehavior="keep"/>
<enableconditions/>
<template>&amp;lt;div id="recaptchaElement"&amp;gt;&amp;lt;/div&amp;gt;</template>
</field>
</fields>
</section>
</sections>
</column>
</columns>
</basicfieldeditor>
<template multiple="false" uniqueid="sk-Wht-266" allowhtml="true">
<contents>&amp;lt;script src="<a href="https://www.google.com/recaptcha/api.js?onload=onloadCallback&amp;amp;render=explicit&quot;" title="Link: https://www.google.com/recaptcha/api.js?onload=onloadCallback&amp;amp;render=explicit&quot;">https://www.google.com/recaptcha/api.js?onload=onloadCallback&amp;amp;render=explicit"</a>;
async defer&amp;gt;
&amp;lt;/script&amp;gt;</contents>
</template>
</components>
<resources>
<labels/>
<javascript>
<jsitem location="inline" name="recaptcha" cachelocation="false" url="">
var captchaCallback = function(data) {
var model = skuid.model.getModel("CaptchaValidated");
model.updateRow(model.getFirstRow(), {isValid:true});
}

var onloadCallback = function() {
grecaptcha.render('recaptchaElement', {
'sitekey' : '6LfXckwUAAAAAPZtN95U_W4UFizPvSCZeC7WUKSc',
'callback': captchaCallback
});
};
</jsitem>
<jsitem location="inlinesnippet" name="recaptchaRefresh" cachelocation="false">var params = argumentst0],
$ = skuid.$;

onloadCallback();</jsitem>
</javascript>
<css/>
<actionsequences uniqueid="sk-Wht-282">
<actionsequence id="c496997b-2e33-49de-82a9-e94178938559" label="ReCaptcha Fired" type="event-triggered" event-scope="component" event-name="captchaFired" uniqueid="sk-Wht-1043">
<description/>
<actions>
<action type="blockUI" message="Done?" timeout="3000"/>
</actions>
</actionsequence>
</actionsequences>
</resources>
<styles>
<styleitem type="background" bgtype="none"/>
</styles>
</skuidpage>

Peter,


In trying to follow your example, I keep getting this error:


There was a problem rendering a component of type basicfieldeditor: grecaptcha is not defined

The page loads fine if I remove the template field and script.

I’ve compared my XML to yours and I do not see what could be causing this issue.

There are a couple fields of type picklist that are required on the Salesforce object. Could this be affecting the recaptcha script?

Thanks,

Or


Looks the cause of the error is an action that is set to fire when any model row is updated and the field is a Salesforce picklist that is required at field level. When the page loads, it looks like it is thinking the model has been updated and tries calling recaptchaRefresh before the fields load on the page. 

Not sure how to resolve though. Your sample is working correctly, except your sample does not have a Salesforce picklist that is required. 


Hi Or,


It sounds like you may only need to trigger the “recaptchaRefresh” snippet when someone updates any field that has a popup, such as date fields or reference fields. Can you adjust your model action so that it only triggers the snippet when those fields are updated, instead of triggering it for any field update?


Hi Or, I wanted to check in and see if my suggestion was useful, or if you’ve been able to get this working.