Robby on Rails: Tracking AJAX-driven events in Ruby on Rails for Google Analytics conversion goalsthoughts.sort_by{|t| t[:topic]}.collect tag:www.robbyonrails.com,2005:TypoTypo2009-10-21T13:14:33-04:00Robby Russellurn:uuid:aa29c8a0-a707-4a4d-9584-5126c65a91e72009-10-21T13:09:00-04:002009-10-21T13:14:33-04:00Tracking AJAX-driven events in Ruby on Rails for Google Analytics conversion goals<p>Tracking your <a href="http://en.wikipedia.org/wiki/Performance_indicator"><span class="caps">KPI</span>’s</a> is extremely important in your online venture. At a minimum, you should be using something like <a href="http://www.google.com/analytics/">Google Analytics</a> to track conversions in your application. Setting up goals is actually quite simple, especially if you’re just tracking that specific pages are loaded. However, if some of your conversion points occur through <span class="caps">AJAX</span>, you might not be capturing those activities in Google Analytics.</p>
<p>Lucky for you, it’s actually <a href="http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer=55520">quite simple to update this</a>. I thought I’d show you a fairly simple example to help you along.</p>
<p>On our web site, we have a mini contact form at the bottom of many of our pages. When submitted, if JavaScript is enabled, it’ll perform an Ajax request to submit the form. If you fill out the main <a href="http://planetargon.com/get-in-touch">Get in Touch</a> form that gets processed and we redirect people to a thank you page. The <span class="caps">URL</span> for that is unique and we’re able to track those in Google Analytics quite easily.</p>
<p>However, with the Ajax-form, the <span class="caps">URL</span> in the browser isn’t going to change so Google Analytics isn’t going to track that conversion. So, we needed to track that properly.</p>
<p>To do this, we just need to call a JavaScript function that the Google Analytics code provides you.</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">pageTracker</span><span class="punct">.</span><span class="ident">_trackPageview</span><span class="punct">("</span><span class="string">/contact_requests/thanks</span><span class="punct">");</span></code></pre></div>
<p>Let’s look at some simple code from our controller action. If the request is from JavaScript, we currently replace the form area with the content in a partial. (<strong>note</strong>: if you’re curious about the <code>_x</code>, read <a href="http://www.robbyonrails.com/articles/2007/08/01/designers-developers-and-the-x_-factor">Designers, Developers and the x_ factor</a>)</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">respond_to</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">format</span><span class="punct">|</span>
<span class="ident">format</span><span class="punct">.</span><span class="ident">html</span> <span class="punct">{</span> <span class="ident">redirect_to</span> <span class="symbol">:action</span> <span class="punct">=></span> <span class="symbol">:thanks</span> <span class="punct">}</span>
<span class="ident">format</span><span class="punct">.</span><span class="ident">js</span> <span class="keyword">do</span>
<span class="ident">render</span> <span class="symbol">:update</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">page</span><span class="punct">|</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">replace</span> <span class="symbol">:x_mini_contact_form_module</span><span class="punct">,</span> <span class="symbol">:partial</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">mini_contact_form_thanks</span><span class="punct">'</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p>As you can see, the redirect will within the <code>format.html</code> block will lead people to our conversion point. However, the <code>format.js</code> block will keep the user on the current page and it’ll not trigger Google Analytics to track the conversion. To make this happen, we’ll just sprinkle in the following line of code.</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">page</span><span class="punct">.</span><span class="ident">call</span> <span class="punct">'</span><span class="string">pageTracker._trackPageview("/contact_requests/thanks");</span><span class="punct">'</span></code></pre></div>
<p>However, if you need to do something like this in several locations in your application, you might want to just extend the JavaScriptGenerator <code>page.</code> GeneratorMethods. (you could toss this in <code>lib/</code>, create a plugin, etc…)</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="keyword">module </span><span class="module">ActionView</span>
<span class="keyword">module </span><span class="module">Helpers</span>
<span class="keyword">module </span><span class="module">PrototypeHelper</span>
<span class="keyword">class </span><span class="class">JavaScriptGenerator</span> <span class="comment">#:nodoc:</span>
<span class="keyword">module </span><span class="module">GeneratorMethods</span>
<span class="comment"># Calls the Google Analytics pageTracker._trackPageview function with +path+.</span>
<span class="comment">#</span>
<span class="comment"># Examples:</span>
<span class="comment">#</span>
<span class="comment">#</span>
<span class="comment"># # Triggers: pageTracker._trackPageview('/contact_requests/thanks');</span>
<span class="comment"># page.track_page_view '/contact_requests/thanks'</span>
<span class="comment">#</span>
<span class="keyword">def </span><span class="method">track_page_view</span><span class="punct">(</span><span class="ident">path</span><span class="punct">)</span>
<span class="ident">record</span> <span class="punct">"</span><span class="string">pageTracker._trackPageview('<span class="expr">#{path}</span>');</span><span class="punct">"</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p>This will allow us to do the following:</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">page</span><span class="punct">.</span><span class="ident">track_page_view</span> <span class="punct">"</span><span class="string">/contact_requests/thanks</span><span class="punct">"</span>
<span class="comment"># or using a route/path</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">track_page_view</span> <span class="ident">thanks_contact_requests_path</span></code></pre></div>
<p>So, our updated code now looks like:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">render</span> <span class="symbol">:update</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">page</span><span class="punct">|</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">replace</span> <span class="symbol">:x_mini_contact_form_module</span><span class="punct">,</span> <span class="symbol">:partial</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">mini_contact_form_thanks</span><span class="punct">'</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">track_page_view</span> <span class="ident">thanks_contact_requests_path</span>
<span class="keyword">end</span></code></pre></div>
<p>With this in place, we can sprinkle similar code for our various conversion points that are Ajax-driven and Google Analytics will pick it up.</p>
<p>Happy tracking!</p><p>Tracking your <a href="http://en.wikipedia.org/wiki/Performance_indicator"><span class="caps">KPI</span>’s</a> is extremely important in your online venture. At a minimum, you should be using something like <a href="http://www.google.com/analytics/">Google Analytics</a> to track conversions in your application. Setting up goals is actually quite simple, especially if you’re just tracking that specific pages are loaded. However, if some of your conversion points occur through <span class="caps">AJAX</span>, you might not be capturing those activities in Google Analytics.</p>
<p>Lucky for you, it’s actually <a href="http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer=55520">quite simple to update this</a>. I thought I’d show you a fairly simple example to help you along.</p>
<p>On our web site, we have a mini contact form at the bottom of many of our pages. When submitted, if JavaScript is enabled, it’ll perform an Ajax request to submit the form. If you fill out the main <a href="http://planetargon.com/get-in-touch">Get in Touch</a> form that gets processed and we redirect people to a thank you page. The <span class="caps">URL</span> for that is unique and we’re able to track those in Google Analytics quite easily.</p>
<p>However, with the Ajax-form, the <span class="caps">URL</span> in the browser isn’t going to change so Google Analytics isn’t going to track that conversion. So, we needed to track that properly.</p>
<p>To do this, we just need to call a JavaScript function that the Google Analytics code provides you.</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">pageTracker</span><span class="punct">.</span><span class="ident">_trackPageview</span><span class="punct">("</span><span class="string">/contact_requests/thanks</span><span class="punct">");</span></code></pre></div>
<p>Let’s look at some simple code from our controller action. If the request is from JavaScript, we currently replace the form area with the content in a partial. (<strong>note</strong>: if you’re curious about the <code>_x</code>, read <a href="http://www.robbyonrails.com/articles/2007/08/01/designers-developers-and-the-x_-factor">Designers, Developers and the x_ factor</a>)</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">respond_to</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">format</span><span class="punct">|</span>
<span class="ident">format</span><span class="punct">.</span><span class="ident">html</span> <span class="punct">{</span> <span class="ident">redirect_to</span> <span class="symbol">:action</span> <span class="punct">=></span> <span class="symbol">:thanks</span> <span class="punct">}</span>
<span class="ident">format</span><span class="punct">.</span><span class="ident">js</span> <span class="keyword">do</span>
<span class="ident">render</span> <span class="symbol">:update</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">page</span><span class="punct">|</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">replace</span> <span class="symbol">:x_mini_contact_form_module</span><span class="punct">,</span> <span class="symbol">:partial</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">mini_contact_form_thanks</span><span class="punct">'</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p>As you can see, the redirect will within the <code>format.html</code> block will lead people to our conversion point. However, the <code>format.js</code> block will keep the user on the current page and it’ll not trigger Google Analytics to track the conversion. To make this happen, we’ll just sprinkle in the following line of code.</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">page</span><span class="punct">.</span><span class="ident">call</span> <span class="punct">'</span><span class="string">pageTracker._trackPageview("/contact_requests/thanks");</span><span class="punct">'</span></code></pre></div>
<p>However, if you need to do something like this in several locations in your application, you might want to just extend the JavaScriptGenerator <code>page.</code> GeneratorMethods. (you could toss this in <code>lib/</code>, create a plugin, etc…)</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="keyword">module </span><span class="module">ActionView</span>
<span class="keyword">module </span><span class="module">Helpers</span>
<span class="keyword">module </span><span class="module">PrototypeHelper</span>
<span class="keyword">class </span><span class="class">JavaScriptGenerator</span> <span class="comment">#:nodoc:</span>
<span class="keyword">module </span><span class="module">GeneratorMethods</span>
<span class="comment"># Calls the Google Analytics pageTracker._trackPageview function with +path+.</span>
<span class="comment">#</span>
<span class="comment"># Examples:</span>
<span class="comment">#</span>
<span class="comment">#</span>
<span class="comment"># # Triggers: pageTracker._trackPageview('/contact_requests/thanks');</span>
<span class="comment"># page.track_page_view '/contact_requests/thanks'</span>
<span class="comment">#</span>
<span class="keyword">def </span><span class="method">track_page_view</span><span class="punct">(</span><span class="ident">path</span><span class="punct">)</span>
<span class="ident">record</span> <span class="punct">"</span><span class="string">pageTracker._trackPageview('<span class="expr">#{path}</span>');</span><span class="punct">"</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span>
<span class="keyword">end</span></code></pre></div>
<p>This will allow us to do the following:</p>
<div class="typocode"><pre><code class="typocode_ruby "> <span class="ident">page</span><span class="punct">.</span><span class="ident">track_page_view</span> <span class="punct">"</span><span class="string">/contact_requests/thanks</span><span class="punct">"</span>
<span class="comment"># or using a route/path</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">track_page_view</span> <span class="ident">thanks_contact_requests_path</span></code></pre></div>
<p>So, our updated code now looks like:</p>
<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">render</span> <span class="symbol">:update</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">page</span><span class="punct">|</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">replace</span> <span class="symbol">:x_mini_contact_form_module</span><span class="punct">,</span> <span class="symbol">:partial</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">mini_contact_form_thanks</span><span class="punct">'</span>
<span class="ident">page</span><span class="punct">.</span><span class="ident">track_page_view</span> <span class="ident">thanks_contact_requests_path</span>
<span class="keyword">end</span></code></pre></div>
<p>With this in place, we can sprinkle similar code for our various conversion points that are Ajax-driven and Google Analytics will pick it up.</p>
<p>Happy tracking!</p>