reCaptcha v2 is being rendered twice after last fix

Wappler v7.3.4

NodeJS SPA, Bootstrap 5

Using CloudFlare Turnstile in reCaptcha v2 compatibility mode

reCaptcha v2 is being rendered twice after last fix, outside conditional regions

Please console.log render attempts and see if it’s being triggered twice

Try adding render=explicit to the script URL. If it is compatible with the google API, it should prevent the auto rendering which conflicts with the App Connect render.

<script src="https://www.google.com/recaptcha/api.js?render=explicit" defer></script>

This double-rendering happens even on SPA page changes, which I assume implicit rendering isn't being executed (because Turnstile without compatibility mode doesn't implicitly render on SPA page changes, as far as my testing goes)

Are you sure you're not calling render twice (in different parts of the AppConnect framework)? You had some code to render reCaptcha on SPA page changes


Compatibility mode requires ?compat=recaptcha

?compat=recaptcha&render=explicit has same double render behaviour (render param might be ignored)
?render=explicit isn't working because it's not reCaptcha compatibility mode

I probably have to update the check that detects if it is already rendered. Currently it looks for an element with class g-recaptcha-response to detect if the recaptcha was already rendered. Turnstyle probably doesn't have the same html structure so I probably can better check for and input or textarea with the name g-recaptcha-response. Could you check the rendered html if that would work with turnstyle.

The rendered HTML of Turnstile compatibility mode looks like this:

<div id="dmxReCaptcha21" class="g-recaptcha recaptcha-center" data-sitekey="1x00000000000000000000AA">
  <div>
    <template shadowrootmode="closed">
      <iframe src="https://challenges.cloudflare.com/"></iframe>
    </template>
    <input type="hidden" name="cf-turnstile-response" id="cf-chl-widget-1zumh_response" value="XXXX.DUMMY.TOKEN.XXXX">
    <input type="hidden" name="g-recaptcha-response" id="cf-chl-widget-1zumh_g_response" value="XXXX.DUMMY.TOKEN.XXXX">
  </div>
</div>

Regarding latest v7.3.6 update, there seems to be a race condition, on SPA fragment changes it's still double-rendered, but on non-SPA fragment changes it's fixed

Edit:
Confirmed race condition, adding a 1 ms delay works:

grecaptcha.ready((() => {
    setTimeout(() => {
        e.querySelector('[name="g-recaptcha-response"]') || grecaptcha.render(e)
    }, 1);
}))

Edit 2:
Another bug introduced by these changes, I can no longer call a callback using attribute data-callback

<div id="dmxReCaptcha21" class="g-recaptcha" data-theme="dark" data-sitekey="<%=_('$_ENV.RECAPTCHA_SITE_KEY',locals)%>" data-callback="callbackTest"></div>
<script>
function callbackTest(t) {
console.log(“callbackTest”);
}
</script>

I was automatically triggering a form submit when the captcha was completed, but now the callback isn’t called

I think that the double rendering on SPA fragment pages is due to some recaptcha code in the routing plugin. I removed the code there since the rendering of the recaptcha is now global.

Update: dmxRouting.zip (9.9 KB)

The double-rendering is now fixed. Can you fix the data-callback attribute? It seems you're inserting your own callback, you have to call the original also (if any)

I did indeed add my own callback, but that is only needed for the google invisible recaptcha within forms. I updated it to only add it there instead of every recaptcha what it did currently.

update: dmxAppConnect.zip (120.8 KB)

Looks good, thanks!

Fixed in Wappler 7.3.7

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.