How To Track HTML 5 Audio Plays Using The Ahoy Gem in Ruby on Rails
If you’re using Ruby on Rails and need an effective way to add analytics to your application use the Ahoy gem. Using the gem is pretty straight forward in that you can simply set it up to track everything with just a small amount of code. For example, once you install the gem:
In your application controller add:
after_action :track_action
protected
def track_action
ahoy.track "Ran action", request.path_parameters
end
In your application.js add:
ahoy.trackAll();
Once you start using the website, you will see new entries for ahoy visits and events in the new database tables created by the install. The documentation provides more information on how to track only what you need and more.
However what it doesn’t track automatically are audio plays when using an HTML 5 player. The code for an HTML 5 player looks like this:
<audio controls controlsList=”nodownload” preload=”auto”>
<source src=”https://yoursite.com/audio.mp3” type=”audio/mp3">
Your browser does not support the HTML5 Audio element.
</audio>
Easy stuff.
In my case, I have built a shopping cart and I have included an audio feature for each product description. While Ahoy can track when the audio starts to play (when someone presses the button) and when the audio ends (when it’s done playing), it doesn’t do this automatically nor does the documentation show you how to enable this tracking.
I was able to figure it out and now I’m showing you how to get this tracking to work. This is particularly useful for podcast websites where I personally feel it’s important to host your own audio and collect your own analytics.
The first thing you need to do is add a little bit to your HTML 5 audio code like so:
<audio id=”play_product_audio” data-product-name=”<%= @product.name %>” controls controlsList=”nodownload” preload=”auto”>
<source src=”<%= @product.audio %>” type=”audio/mp3">
Your browser does not support the HTML5 Audio element.
</audio>
You will need to give the element an “id” and you will want to define the product name as well. This is so the actual name of the product is added to the event in the database, otherwise, you won’t know which product the visitor played the audio for.
Next you need to add a little JavaScript to get this to work. I added this script to the bottom of the product show page but you can add it wherever you like.
<script>
var sound = document.getElementById(“play_product_audio”);
var productName = sound.dataset.productName;sound.onplay = function(){
ahoy.track(“Product Audio Play”, {product: productName} );
};sound.onended = function(){
ahoy.track(“Product Audio Ended”, {product: productName} );
};
</script>
First we create a “sound” variable (you can use whatever you like) and set it to the audio player which is identified by the “id” we gave it.
Then we created a “productName” variable and set it to the data-product-name we added to the player.
So we then take our sound variable and create a function to track when the audio is played (onplay) and when the audio ends (onended). “onplay” and “onended” are global event handlers for the HTML 5 player. There are many more you can track.
When someone plays the audio, an event is created in the ahoy events table with the “name” set to “Product Audio Play” and “properties” set to {“product”: “Name of Product”}. There is a similar entry when the audio ends.
Now, you can do something like the following in a controller and view to keep track of how many times each audio file has been played.
In the controller:
@product_audio_plays = Ahoy::Event.where(name: “Product Audio Play”).group(:properties).count
In the view:
<table>
<thead>
<tr>
<th>Product</th>
<th>Count</th>
</tr>
</thead>
<tbody>
<% @product_audio_plays.each do |key,val| %>
<tr>
<td><%= key %></td>
<td><%= val %></td>
</tr>
<% end %>
</tbody>
</table>
That’s it!
…well, for that use case anyway. What happens when you have multiple players on the same page?
You tear your hair out.
Then you figure it out and share it with the rest of the world.
You see, I’d also added an audio feature to the Frequently Asked Questions page. All of the FAQs are on the same page and each one has an audio file associated with it. I needed to do the exact same thing to track audio plays for the FAQs. But it wasn’t so easy because there are multiple players on one page.
On the FAQs view page we do something similar with our audio code that we did for the product audio.
<audio id=”play_faq_audio_<%= question.id %>” data-faq-question=”<%= question.question %>” controls preload=”auto”>
<source src=”<%= question.file %>” type=”audio/mp3">
Your browser does not support the HTML5 Audio element.
</audio>
Do you see the difference?
For this use case, we have to make the “id” unique so we need to add the FAQ question id to the id. So the id for each player will be unique.
That was pretty easy to figure out but not really knowing much JavaScript, figuring out the rest took a while. It’s all good though. You learn something new every day.
Again, I added the JavaScript to the bottom of the FAQs view page as the following:
<script>
var x, i;
x = document.querySelectorAll(“[id^=’play_faq_audio_’]”);
for (i = 0; i < x.length; i++) {
let faqQuestion = x[i].dataset.faqQuestion;
x[i].onplay = function(){
ahoy.track(“Faq Audio Play”, {question: faqQuestion} );
};
x[i].onended = function(){
ahoy.track(“Faq Audio Ended”, {question: faqQuestion} );
};
}
</script>
Right away you should notice some differences between this script and the one used for the product audio.
The biggest difference is that now we have to use querySelectorAll to get the id based on a partial identifier. Then we needed some kind of counter “i” so we could loop through each of the players on the page. For each of those players we set “faqQuestion” to the data-faq-question we set for the player.
Then we can do something similar for the ahoy tracking but “x” is going to be “play_faq_audio_” and [i] is going to be whatever number is provided by the counter.
When someone plays any one of the audio files on the one page, an event will be created and for the “name” it will have “Faq Audio Play” for the value and the properties will have {“question”: “Your question?”} as the value. A similar entry will be made when the audio ends.
Then you can also create a table to view the analytics for the FAQ audio.
In whatever controller you are using for analytics, you can do something like:
@faq_audio_plays = Ahoy::Event.where(name: “Faq Audio Play”).group(:properties).count
Then in your analytics view you can create a table like this:
<table>
<thead>
<tr>
<th>Question</th>
<th>Count</th>
</tr>
</thead>
<tbody>
<% @faq_audio_plays.each do |key,val| %>
<tr>
<td><%= key %></td>
<td><%= val %></td>
</tr>
<% end %>
</tbody>
</table>
Now you will have tracking for a single player on a page and multiple players on a page.
NOTE: I’m not a JavaScript developer so I may be lacking on explaining the “counter” but you can see how it works. Even with my JavaScript skills I was able to search and weed through enough information to figure it out and get it to work.
Rails version: 6.0.3