3

I have Optimizely on a page that also has a Google Form on it, and I want to track events when the form is submitted. This is roughly the code I have now:

  window.optimizely = window.optimizely || [];
  $('#ss-form').on('submit', function() {
    window.optimizely.push(['trackEvent', 'submit']);
  });

The problem is that it's severely under-reporting the number of submits that actually happen.

The only explanation I could come up with (and so did Optimizely support) is that most of the time the form is getting submitted and the next page is getting loaded before the optimizely tracking code finishes running. It has to make a request to Optimizely before the form POST request is made to Google, so its running time is probably non-negligible.


How do I ensure that the whole callback will definitely run to completion before the form is submitted?

P.S.: Optimizely support mentioned this might also have something to do with the fact that the page is hosted on one domain and submits to a different one (Google's), but I'm not sure if that has anything to do with this.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
agentofuser
  • 8,987
  • 11
  • 54
  • 85
  • `optimizely` needs to emit an event when it's done. It's hard to impossible otherwise. – John Dvorak Nov 30 '12 at 11:24
  • @JanDvorak is the hypothesis correct though? Is that the cause of underreporting? Why would the browser allow the form submission/page load to interrupt an `onsubmit` callback? Doesn't that defeat the purpose of having this specific event altogether? It's kind of useless if you can't trust it to perform its work right? – agentofuser Nov 30 '12 at 11:29
  • You could track the event from the other page (where the form is submitted to) – John Dvorak Nov 30 '12 at 11:30
  • The other page is the Google Form's "thank you" page, and I don't have control over it (can't add js to it). – agentofuser Nov 30 '12 at 11:31
  • The only problem is that when the page is unloaded, all pending XHRs are aborted. The script itself does finish, but the ajax doesn't have the time to leave. – John Dvorak Nov 30 '12 at 11:31
  • You could submit to a log&redirect page. – John Dvorak Nov 30 '12 at 11:32
  • Hm... interesting. Any way I can force it to wait for all pending XHRs to go through first? – agentofuser Nov 30 '12 at 11:32
  • You could prevent the submit, wait a few milliseconds, then trigger the submit manually. – John Dvorak Nov 30 '12 at 11:33
  • Is there a way to tell Optimizely to make synchronous calls? – John Dvorak Nov 30 '12 at 11:35
  • That would still be non-deterministic, right? It would probably catch more submits, but still might miss some that take longer than whatever timeout I set? – agentofuser Nov 30 '12 at 11:35
  • I _think_ there's only one AJAX to leave. In that case, waiting should be reliable (once it starts, timeout callbacks will have to wait, and it should start immediately). – John Dvorak Nov 30 '12 at 11:37
  • I vote for log&redirect, or ditching Optimizely completely. – John Dvorak Nov 30 '12 at 11:41
  • or a third option, send your own _synchronous_ AJAX manually to do the logging. – John Dvorak Nov 30 '12 at 11:42
  • About the waiting option, would that be just calling a `setTimeout(fn, 0)` after the `optimizely.push()` code, inside the `onsubmit` callback code? – agentofuser Nov 30 '12 at 11:43
  • In jQuery, synchronous AJAX is as easy as setting the `async` option to false: http://api.jquery.com/jQuery.ajax/ – John Dvorak Nov 30 '12 at 11:44
  • 1
    `setTimeout(fn, 0)` _should_ work. No promises, though. – John Dvorak Nov 30 '12 at 11:45
  • Re: setting `async` to false, I would have to find the xhr call in their minified code and monkeypatch it though, right? Will try `setTimeout` and report back. – agentofuser Nov 30 '12 at 11:47
  • You should be able to call their logging calls from your own server page to which you could submit manually through your own `$.ajax({async:false, ...` call – John Dvorak Nov 30 '12 at 11:48
  • also note if you set the timeout to anything shorter than 4ms, the browser will wait for 4ms anyways: http://jsperf.com/smallest-timeout – John Dvorak Nov 30 '12 at 11:52
  • Or you could find what optimizely actually sends, and replicate the behavior with synchronous ajax. – John Dvorak Nov 30 '12 at 11:58
  • What about setting a note in `localStorage` or a cookie that you should submit a tracking event? – John Dvorak Nov 30 '12 at 12:01
  • Re: the server page, I don't have a server, that's what I was trying to avoid. I'm just serving a static HTML and capturing results on a Google Spreadsheet. And re: cookie and localStorage, I can't add JS to the form submission confirmation page, so I wouldn't be able to look into the stored note to submit the event afterwards. The general question bugs me though: how can it be that the API offers a callback on an event and then doesn't guarantee it will be run? – agentofuser Nov 30 '12 at 14:34
  • The callback (`submit`) does always run, and always finishes. AJAX also always calls its callback. The only case when a callback is not called is when the page unloads - and this has to happen - the browser _has_ to kill the javascript at some point. Even then, the 'unload' event is guaranteed to be called and finish. – John Dvorak Nov 30 '12 at 15:16

0 Answers0