Problems Integrating Elm with Google Analytics/gRecaptcha

I need to get the google_client_id and use it in my Elm app.

I need this value in the Flags because depending on the route I need to make a request to the server in the init.

The value is extracted in JS using ga.getAll()[0].get("clientId")

Now, the problem is that Google Analytics loads async so, I thought that I would wait a little bit and ended up writing something like:

var app; 
function start(){
  if( && {
  app = Elm.Main.init({flags: {"user": flags, "today": today, 
      i18n: translations, hosts: window.hosts, 

  app.ports.loadCaptcha.subscribe(function(unit) { 
      grecaptcha.execute('__SITE_KEY__', {action: 'homepage'}).then(function(token) {     
  else {

This solves the init availability of the clientId BUT it breaks grecaptcha
Now, when I try to check the captcha state I get a Timeout error like this.

recaptcha__en.js:519 Timeout (n)
(anonymous)	@	recaptcha__en.js:519
Promise.catch (async)		
cL.dY	@	recaptcha__en.js:518
XQ	@	recaptcha__en.js:512
validate	@	app.js:27710
(anonymous)	@	app.js:27741
(anonymous)	@	app.js:2616
A3	@	app.js:513
(anonymous)	@	app.js:2420
_Scheduler_step	@	app.js:2264
_Scheduler_enqueue	@	app.js:2226
(anonymous)	@	app.js:2254
(anonymous)	@	app.js:2284
setTimeout (async)		
(anonymous)	@	app.js:2283
(anonymous)	@	app.js:27642
_Scheduler_step	@	app.js:2252
_Scheduler_enqueue	@	app.js:2226
_Scheduler_rawSend	@	app.js:2172
_Platform_dispatchEffects	@	app.js:2499
sendToApp	@	app.js:2328
callback	@	app.js:3597
t._rollbar_wrapped.t._rollbar_wrapped	@	rollbar.min.js:1

The grecaptcha works just fine if I start the app without wrapping it in that function.

Any of you has any idea why would things break if I start Elm like that? Also, is there any alternative approach I could take?

1 Like

How are you loading analytics and recaptcha? Without that information it is hard to know what may be going on.

Regardless, maybe organizing the scripts by order and making them defer instead of async would make them run in order. There is also the load event on script tags, so maybe listen for that.

Also, using requestAnimationFrame for this is super aggressive. Checking every 16 ms is a lot and is going to hurt performance. A more relaxed setTimeout with 300 or so would work well and still be basically unnoticeable to users.

I’m using the official google recommendation. The analytics are part of the Google Tag Manager and I just used the information from the Quick Start Guide:

I’m using the recaptcha v3 and loading it is just adding the script to the head:

On a submit, I send a message to JS using ports, execute the recaptcha as seen in the above code and push the token back into Elm.

I have no idea why recaptcha is failing if I start the Elm app inside that function.

This happens only once, to start the app and as soon as google analytics becomes available I’m starting the Elm app. The app has nothing else to do than wait for that library to become available.

I also tried setTimeout and it too breaks the recaptcha integration.

One alternative could be to load elm right away and send the analytics id in via a port when it is loaded

This is what I was trying to avoid. Basically, each page when it loads makes a request to the backend that now needs to include the google_client_id. If this is not easily available as flags, I’m left with deferring the loading of the page until I get the the google_client_id through ports. This is what I will implement if I find no other solution.

What I ended up doing is have a two way communication between Elm and JS where Elm checks to see if ga is ready and when it gets ready the google_client_id is sent back to Elm and it is saved in the model.

The functionality that needed the client_id got extracted from the init and delayed until the field in the model is set.

1 Like

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